2012-12-22 20 views
5

在我看來,當我在對象類的委託方法上使用WeakReference類時,對象類由GC收集,但仍有另一個副本駐留在WeakReference中?WeakReference引用委託時GC不會收集?

我覺得很難用文字解釋。我會舉一個例子。我有一個名爲TestObject以下對象類:現在

class TestObject 
{ 
    public string message = ""; 

    private delegate string deleg(); 

    public TestObject(string msg) 
    { 
     message = msg; 
    } 

    public Delegate GetMethod() 
    { 
     deleg tmp = this.TestMethod; 
     return tmp; 
    } 

    public string TestMethod() 
    { 
     return message; 
    } 

} 

,在我的主要應用程序,我試圖通過WeakReference來引用方法TestMethodTestObject。這樣做的目的是當所有硬引用都消失時,GC可以收集到TestObject。這是我的主要的應用程序看起來像:

static void Main(string[] args) 
    { 
     var list = new List<WeakReference>(); 
     var obj = new TestObject("Hello 1"); 
     list.Add(new WeakReference(obj.GetMethod())); 
     Console.WriteLine("Initial obj: " + ((Delegate)list[0].Target).DynamicInvoke());  //Works fine 
     obj = null;  //Now, obj is set to null, the TestObject("Hello 1") can be collected by GC 
     GC.Collect(); //Force GC 
     Console.WriteLine("Is obj null: " + ((obj) == null ? "True" : "False")); 
     Console.WriteLine("After GC collection: " + ((Delegate)list[0].Target).DynamicInvoke()); 
     Console.ReadKey(); 
    } 

這是輸出,當我運行上面的代碼:

enter image description here

下面是奇怪的事情。 在第一行obj可能會打印"Hello 1",因爲它剛剛初始化並且obj持有對TestObject的引用。全對了。接下來,obj被設置爲nullobj = null並且GC被迫收集。所以,輸出,obj的第二行true爲空。最後一行最後一行,由於GC已收集到obj,我期待它或者拋出NullReferenceException或者只是在輸出上不打印任何東西。但是,它實際上是在輸出的第一行打印了相同的內容! GC現在應該不會收集TestObject?!

這引出了一個問題,即在將obj設置爲null後,最初在obj中保存的TestObject是否已由GC收集或未收集。

如果我已將整個對象傳遞到WeakReferencenew WeakReference(obj)而不是委託給WeakReference,它將完美地工作。

不幸的是,在我的代碼中,我需要將代碼傳遞給WeakReference。我如何讓WeakReference正常工作,以便GC可以通過僅引用委託來收集對象?

回答

5

我認爲問題出在您的測試中 - 而不是在框架中。看起來,將局部變量設置爲null並不符合你的期望。如果我們完全跳過了本地變量,我們得到了預期的NullReferenceException的「後」線:

static void Main(string[] args) 
{ 
    var list = new List<WeakReference>(); 
    //var obj = new TestObject("Hello 1"); 
    list.Add(new WeakReference(new TestObject("Hello 1").GetMethod())); 
    Console.WriteLine("Initial obj: " + ((Delegate)list[0].Target).DynamicInvoke());  //Works fine 
    //obj = null;  //Now, obj is set to null, the TestObject("Hello 1") can be collected by GC 
    GC.Collect(); //Force GC 
    //Console.WriteLine("Is obj null: " + ((obj) == null ? "True" : "False")); 
    Console.WriteLine("After GC collection: " + ((Delegate)list[0].Target).DynamicInvoke()); 
    Console.ReadKey(); 
} 
0

其實你的例子會按預期運行,因爲你什麼都沒有,除了WeakReference的是指代表,所以GC可以收集它,即使你註釋掉「obj = null」這一行!

This is my result

也許是因爲我運行一個獨立的線程(除主線程)的代碼?

相關問題