GCHandle.Alloc(Object) 的合约到底是啥?

Posted

技术标签:

【中文标题】GCHandle.Alloc(Object) 的合约到底是啥?【英文标题】:What exactly is the contract of GCHandle.Alloc(Object)?GCHandle.Alloc(Object) 的合约到底是什么? 【发布时间】:2011-12-03 01:11:12 【问题描述】:

我想对 GCHandle.Alloc(Object) 的合约有一个严谨的理解。

我从文档中了解到,如果我打电话:

GCHandle gc = GCHandle.Alloc(foo);

在我调用之前,foo 将被保证不会被垃圾回收:

gc.Free();

我也明白,如果 AppDomain 被卸载,foo 将被收集。

我想检查的是,在没有调用 Free 的情况下调用 Alloc 是否实际上与根引用相同(在 GC 眼中)。

如果这是真的,那么 GCHandle 变量 gc 的范围对 foo 的生命周期没有影响。如果 Free 不被称为 foo 直到 AppDomain 卸载。

例如 一个对象在自身上调用 Alloc 并且不保留 GCHandle 实例,它会一直存在直到 AppDomain 被卸载。

这对吗?

一些参考资料:

http://msdn.microsoft.com/en-us/library/a95009h1.aspx

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.gchandle.free.aspx

http://blogs.msdn.com/b/clyon/archive/2005/03/18/398795.aspx

【问题讨论】:

为什么我感觉有人会试图利用这种行为? 很多已经有了。它被称为单例模式,你不需要使用 GCHandle 来完成它。只需创建对对象的静态引用。除非清除引用,否则不会收集它。 @Jim 老实说,我只是想澄清一下我的理解——我没有计划一个应用程序域的长生命周期(我正在寻找作为非托管代码回调的委托的安全生命周期和认为这个澄清会很有用)。 【参考方案1】:

正确。 GCHandle 变量对传递给 GCHandle.Alloc() 的对象的生命周期没有影响。我用以下两个类验证了这一点:

class Test

   public Test ()
   
      System.Runtime.InteropServices.GCHandle.Alloc(this);
   
   ~Test ()
   
   

class Server : MarshalByRefObject

   public Server ()
   
      new Test();
   
   public void Collect ()
   
      GC.Collect();
      GC.WaitForPendingFinalizers();
   

以及下面的测试代码:

AppDomain ad = AppDomain.CreateDomain("test");
Server svr = (Server)ad.CreateInstanceAndUnwrap(
   System.Reflection.Assembly.GetExecutingAssembly().FullName, 
   typeof(Server).FullName);
for (Int32 i = 0; i < 100; i++)
   svr.Collect();

使用此示例,如果您在 Test 类的终结器中设置断点,您会注意到在任何 GC.Collect/WaitForPendingFinalizers 调用期间都不会调用它。但是,当卸载 appdomain 时,会触发断点。

【讨论】:

谢谢你 - 我使用带有 !finalizequeue 的 sos.dll 对你的示例进行了一些测试 - 这已经支持了结论

以上是关于GCHandle.Alloc(Object) 的合约到底是啥?的主要内容,如果未能解决你的问题,请参考以下文章

C# 获取普通USB摄像头的像素数据,并将还原成图片。。。

利用Unity自带的合图切割功能将合图切割成子图

OIDC, Oauth2.0 , SMAL 的合而不同

使用雪花中的合并将值插入表并根据条件删除行

小米OJ-找出可能的合的组合深搜(dfs)

小米OJ 12. 找出可能的合的组合