2011-10-07 114 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