当WeakReference引用委托时,GC不会收集?

时间:2012-12-22 23:51:54

标签: c# delegates weak-references

在我看来,当我在对象类的委托方法上使用WeakReference类时,对象类会被GC收集,但是还有另一个副本驻留在{{1}中}?

我发现用文字解释很难。我举个例子。我有以下名为WeakReference的对象类:

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; } } 引用TestMethod中的方法TestObject。目的是当所有硬引用都消失时,GC可以收集WeakReference。这就是我的主要应用程序的样子:

TestObject

这是我运行上述代码时的输出:

enter image description here

这是奇怪的事情。 在第一行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(); } 可以打印obj,因为它刚刚初始化,"Hello 1"持有对obj的引用。全对了。接下来,TestObject设置为obj null,GC被迫收集。因此,在输出的第二行中,obj = nullobj为空。最后在最后一行,因为GC收集了true,我希望它能抛出obj或者只输出输出。但是,它实际上打印的内容与输出的第一行相同!此时GC不应该收集NullReferenceException吗?!

在我将obj设置为null之后,如果TestObject中首次保存的TestObject后来被GC收集了,那么这就引出了一个问题。

如果我将整个对象传递到obj,即WeakReference,而不是委托进入new WeakReference(obj),那么它将完美地运行。

不幸的是,在我的代码中,我需要传递给WeakReference代理人。如何使WeakReference正常工作,以便GC只能通过引用委托来收集对象?

2 个答案:

答案 0 :(得分:6)

我认为问题出在你的测试中 - 而不是在框架中。似乎将局部变量设置为null并不能达到预期效果。如果我们完全跳过局部变量,我们在'after'行得到预期的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();
}

答案 1 :(得分:0)

实际上你的例子会按预期运行,因为除了WeakReference引用了Delegate之外什么都没有,所以GC可以收集它,即使你注释掉“obj = null”行!

This is my result

也许是因为我在一个独立的线程上运行代码(除主线程外)?