我有一个.NT类,它有多个来自本机代码的回调委托。是否有必要分配所有代表?我的意思是GCHandle.Alloc()
只保护委托或拥有代表的整个班级被收集?是否有必要在一个类中的每个回调gchandle.alloc()?
回答
委托具有两个相关的属性,方法和目标。如果委托是为实例方法创建的,则目标将为非null。并且只要垃圾收集器可以看到委托实例,该对象就会保持活动状态。
原生代码与回调问题有关。将委托实例传递给pinvoked本地函数时,P/Invoke编组器将使用Marshal.GetFunctionPointerForDelegate()创建一个存根,以在本机代码进行回调时生成所需的Target引用。然而,垃圾收集器不能看到这个存根,因此不会找到对委托对象的引用。并收集它。本地代码的下一次回调会导致崩溃。
为了避免这种情况,您必须自己存储委托对象,以便只要本机代码可以进行回调,它就会保持引用状态。将它存储在一个静态变量中是一个明显的解决方案。
我想在你存储委托对象的时候会发生错误(但通常不会)。我们都知道,托管内存将由Garbage Collect进行安排。 (这意味着被管理对象的物理内存地址将被改变。)
成像有一个长时间的代理被本地代码调用,我们将代理设置为静态成员或类成员。但有时(我们不知道什么时候,我们只知道它会发生),GC安排了内存,并且委托的物理内存可能从0x000000A到0x0000010。但是本地代码对此一无所知,对于本地代码,它只知道永远调用0x000000A。 所以我们不仅要存储委托对象,而且要使用GCHandle.Alloc来告诉GC不要移动委托对象的物理内存。然后,本地代码在回调时会表现良好。
那么,因为GC没有频繁地安排管理内存,所以对于短期生命代表,即使你不叫GCHandle.Alloc,你的代码总是“做得好”,但有时它会发疯。 现在,你知道原因。
参考: http://dotnet.dzone.com/news/net-memory-control-use-gchandl
当您使用GCHandle.Alloc时,您不需要固定委托 – 2013-10-12 10:41:08
我错了。 您不需要固定委托(另一方面,您不能固定委托,将会抛出异常(System.ArgumentException:Object包含非原始数据或非可读数据。)
参考:关于克里斯Brumme的博客http://blogs.msdn.com/cbrumme/archive/2003/05/06/51385.aspx
详情: 按照同样的思路,管理代表可以被编排到非托管代码,在那里它们被暴露非托管函数指针。呼吁那些指针将执行非托管到受管理的转换;呼叫约定的改变;进入正确的AppDomain;和任何必要的参数编组。很明显,非托管函数指针必须引用一个固定地址。如果GC重新定位那将是一场灾难!这导致许多应用程序为委托创建一个固定句柄。这完全没有必要。非托管函数指针实际上是指我们动态生成的本地代码存根,以执行编组转换。该存根存在于GC堆外的固定存储器中。
但是,应用程序负责以某种方式延长委托的生命周期,直到不再有来自非托管代码的调用发生。本机代码存根的生存期与代理的生存期直接相关。一旦收集到委托,通过非托管函数指针进行的后续调用将崩溃或以其他方式破坏进程。在我们最近发布的版本中,我们添加了一个Customer Debug Probe,它允许您干净地检测代码中的这一点 - 这些都很常见 - 。如果您在开发过程中尚未开始使用客户调试探针,请查看!
- 1. 是否有必要处理每个ManagementObject?
- 2. 是否有必要在Java中的每个类中都有构造函数
- 3. 是否有必要在每个活动中初始化Firebase Analytics?
- 4. 是否有必要在每个类图中添加日志记录和审计
- 5. 在Java Swing中是否有必要始终拥有一个Container?
- 6. 是否有必要在foriegn表中有一个主键?
- 7. 是否有必要在顶层包装每个异常?
- 8. 是否有必要在main中声明一个函数?
- 9. 是否有必要在C++中初始化一个字符串?
- 10. 是否有必要在一个ID内有一个ID的CSS选择器?
- 11. 是否有必要在任何网页至少有一个`H1`?
- 12. 是否有一个MVC Action必须返回一个actionResult?
- 13. 调解员是否必须在PureMvc中拥有一个视图?
- 14. 是否有必要为每个代码块添加try catch
- 15. 是否有必要在类声明的类上下文中指定每个超类?
- 16. 是否有必要在CodeIgniter的每个控制器中加载视图?
- 17. PHPExcel:一旦你有一个对象,是否有必要getSheet?
- 18. 脊椎 - 是否有一个after_activated回调
- 19. 我是否必须在每个类中使用“包”术语
- 20. 是否有必要在Zend Framework 2中的每个PHPUnit测试方法中为所有表类创建模拟?
- 21. 在nodejs的每个回调之后,我是否必须检查错误?
- 22. 从多个类调用setOnClickListener是否只导致一个回调?
- 23. 是否有必要在.net中明确地配置每个对象?
- 24. 调用ZipArchive :: close() - 是否有必要?
- 25. 是否有必要调用ApplicationContext.start
- 26. 是“返回”;在Node.JS中使用回调时必要/有用吗?
- 27. 这个中断()是否必要?
- 28. 是否有必要有base64_encode
- 29. 是否有必要在使用Junit TDD的方法中返回?
- 30. 是否有必要召回在C++中继承类的公共部分的宏
有点晚了评论,但确实存储在一个'static'变量也阻止重排在其他答案中提到? – rmobis 2014-12-02 14:36:42
钉住一个物体是完全不同的东西,而不是这里的主题。回拨代表不需要固定。 – 2014-12-02 14:49:30
其他答案(以及我检查过的其他一些资源)确实提到过,如果回调委托被移动到不同的地址,那么当尝试调用它时,本地层会崩溃,因为它拥有的地址不再有效。还是我错了? – rmobis 2014-12-02 14:52:22