6

在我看来,当我在WeakReference对象类的委托方法上使用该类时,对象类被 GC 收集,但它的另一个副本仍然存在于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通过WeakReference. 目的是TestObject当所有硬引用都消失时,GC 可以收集它们。这是我的主要应用程序的样子:

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被设置为nullwithobj = null并且 GC 被强制收集。因此,在输出的第二行中objtrue空。最后在最后一行,由于 GC 已经收集了obj它,我希望它要么抛出 aNullReferenceException要么在输出上不打印任何内容。但是,它实际上打印了与输出的第一行相同的内容!此时不应该TestObject由GC收集吗?!

这引出了一个问题,如果在我将 obj 设置为 null 之后,GC 后来是否收集了TestObject最初保存的。obj

如果我将整个对象传递给WeakReference,即 ,new WeakReference(obj)而不是将委托传递给WeakReference,它会完美地工作。

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

4

2 回答 2

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();
}
于 2012-12-23T00:07:35.357 回答
0

实际上,您的示例将按预期运行,因为除了 WeakReference 指代委托之外,您什么都没有,因此即使您注释掉“obj = null”行,GC 也可以收集它!

这是我的结果

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

于 2013-10-15T08:05:42.423 回答