【C#】对“xxxx::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用。
来源:互联网 发布:杭州淘宝城附近楼盘 编辑:程序博客网 时间:2024/05/10 18:45
最近在做项目的时候,出现了几次“对“xxxx::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。”异常。
这种错误,一般出现在托管代码调用非托管代码的过程中,如C#程序要调用c++的某个函数,而这个函数正好有个callback函数。当C#调用完之后,GC有可能会把这个callback给回收掉,如果C++接下来的某个函数中也同样使用了这个callback,就会抛出上述异常。因为C++是非托管的,GC又不知道它接下来还要使用callback所以就把它回收掉了。
这个时候,微软就建议我们使用GC.KeepAlive()方法解决,参考官网例子
KeepAlive 方法的目的是确保对对象的引用存在,该对象有被垃圾回收器过早回收的危险。这种现象可能发生的一种常见情形是,当在托管代码或数据中已没有对该对象的引用,但该对象仍然在非托管代码(如 Win32 API、非托管 DLL 或使用 COM 的方法)中使用。
另一种过早发生垃圾回收的情形是,在一个方法中创建并使用一个对象。此时,当对对象的某个成员的调用仍在执行时,可能会对该对象进行回收,如第一个代码示例所示。
此方法引用 obj,从而使该对象从例程开始到调用此方法的那个位置(按执行顺序)均不符合进行垃圾回收的条件。在 obj 必须可用的指令范围的结尾(而不是开头)编写此方法的代码。
KeepAlive 方法除了延长作为参数传递的对象的生存期之外,不会执行任何操作,也会不产生任何其他副作用。
MSDN上有官方例子可以参考下。我在这里贴出我的代码:
private InteropHelper.MKDriverAcceptGatewayConnectCallback connectCallback;private InteropHelper.MKDriverAcceptGatewayErrorCallback errorCallback; public void cbMKDriverAcceptGatewayConnect(IntPtr dref, IntPtr sref, IntPtr addr, int socklen) { //... } public void cbMKDriverAcceptGatewayErrorCallback(IntPtr dref, int error) { //... } private void XtraForm1_Load(object sender, EventArgs e) { connectCallback = new InteropHelper.MKDriverAcceptGatewayConnectCallback(cbMKDriverAcceptGatewayConnect); errorCallback = new InteropHelper.MKDriverAcceptGatewayErrorCallback(cbMKDriverAcceptGatewayErrorCallback); drvRef = InteropHelper.MKDriverCreate(); if (drvRef == IntPtr.Zero) { MessageBox.Show("加载接口失败"); } else { InteropHelper.MKDriverSetCb(drvRef, connectCallback, errorCallback); GC.KeepAlive(connectCallback);//关键的两句 GC.KeepAlive(errorCallback);//关键的两句 //如果没有上面的这两句KeepAlive,MKDriverSetCb调用完之后,两个callback就被GC.Collect掉了,以后如果还有调用的话就会抛异常。 timer1.Enabled = true; } } private void timer1_Tick(object sender, EventArgs e) { //间隔10ms if (drvRef != IntPtr.Zero) { if (InteropHelper.MKDriverDispatch(drvRef, 0, 0) != 0) { //就是因为上面Load方法内两句GC.KeepAlive没有加,所以在这里会不定时抛出异常。谁知道搞C++的那帮人在MKDriverDispatch里也调用了callback。 GMessageBox.Wrong("接口授权过期"); return; }
欢迎大家,评论交流。
- 【C#】对“xxxx::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用。
- 类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们的问题的解决方法
- 类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们的问题的解决方法 续集
- 对“demo!demo.Index+HookProc::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活
- 向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们
- .net CallBack::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩
- 对“XXX::Invoke”类型的已垃圾回收委托进行了回调
- .net CallbackOnCollectedDelegate 垃圾回收问题。 (Handle::Invoke”类型的已垃圾回收委托进行了回调。)
- C#处理C++库回调报错_非托管代码传递委托被垃圾回收
- C#处理C++库回调报错_非托管代码传递委托被垃圾回收
- 如果非托管代码需要多次调用托管代码中的回调,请将委托的引用保存为成员变量
- 委托事件与托管代码
- 正在调用的委托被垃圾回收
- 托管应用程序和非托管应用程序
- 什么是托管应用程序和非托管应用程序
- 托管应用程序和非托管应用程序
- 应用程序委托/cocos委托
- ios应用程序和应用程序委托
- 使用jmeter进行http接口测试
- Linux 动态链接库和静态库示例
- 基于 Quartz 开发企业级任务调度应用
- bootstrap datetimepicker的两个设置
- JPA-@oneToOne
- 【C#】对“xxxx::Invoke”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用。
- 滴滴WebApp实践经验分享
- study-16:HTTP协议 + Apache2.2
- JVM调优总结(一)-- 一些概念
- 转载 2016最新Java学习计划
- 在广播接收器中启动活动和弹出对话框
- [LeetCode]Number of Islands
- STL之list容器详解
- 量子力学最新发现:人不会真正死去