2011-10-07 100 views
3

我想对GCHandle.Alloc(Object)的合约有一个严格的理解。GCHandle.Alloc(Object)的合同究竟是什么?

我从文档明白,如果我称之为:

GCHandle gc = GCHandle.Alloc(foo); 

foo将保证不会被垃圾收集,直到我打电话:

gc.Free(); 

我也明白,foo将得到回收,如果AppDomain被卸载。

我想检查的是,如果呼叫Alloc而不呼叫Free是否与根引用实际上是相同的(在GC的眼中)。

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

E.g. 一个对象自己调用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

+0

为什么我会觉得有人会尝试利用这种行为? –

+0

许多已经有。它被称为单例模式,你不需要使用GCHandle来完成它。只需创建一个对象的静态引用。除非参考文件被清除,否则不会被收集。 –

+0

@Jim我老实说只是要求澄清我的理解 - 我没有计划一个应用程序域的长生命周期(我正在考虑将代码封装成非托管代码回调的安全生命周期,并认为这个说明会很有用) 。 – morechilli

回答

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(); 

使用这个例子中,如果设置的测试类的终结断点,你会注意到,这是在任何GC.Collect/WaitForPendingFinalizers调用期间未调用。但是,当appdomain被卸载时,断点是命中的。

+0

谢谢你 - 我用你的例子用sos.dll做了一些测试!finalizequeue - 这已经支持了结论 – morechilli