Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GC doesn't collect when WeakReference references a delegate?

It seems to me that when I use the WeakReference class on a delegate method of an object class, the object class gets collected by the GC but there is still another copy of it residing in the WeakReference?

I find it difficult to explain in words. I will give an example. I have the following object class called 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;
    }

}

Now, in my main application, I attempt to refer to the method TestMethod in TestObject via a WeakReference. The intention is so that the TestObject can be collected by GC when all hard references are gone. This is how my main application looks like:

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

This is the output when I run the above code:

enter image description here

Here's the weird thing. On the first line, obj could print "Hello 1" because it was just initialised and obj was holding a reference to the TestObject. All correct. Next, obj was set to null with obj = null and GC was forced to collect. So, in the second line of the output, obj is true to be null. Finally on the last line, since the GC has collected the obj away, I'm expecting it to either throw a NullReferenceException or just print nothing on the output. However, it actually printed the same thing as on the first line of the output! Shouldn't the TestObject be collected by the GC at this point already?!

This begs the question if the TestObject that was first held in obj was later collected by the GC or not after I set obj to null.

If I had passed the whole object into WeakReference, ie, new WeakReference(obj), instead of a delegate into the WeakReference, it would have worked perfectly.

Unfortunately, in my code, I need to pass into the WeakReference a delegate. How can I have the WeakReference to work correctly so that the GC can collect away the object by only having referenced to a delegate?

like image 817
Carven Avatar asked Dec 22 '12 23:12

Carven


People also ask

When to use weak reference?

Use long weak references only when necessary as the state of the object is unpredictable after finalization. Avoid using weak references to small objects because the pointer itself may be as large or larger. Avoid using weak references as an automatic solution to memory management problems.

What is the purpose of weak reference c#?

A weak reference allows the garbage collector to collect an object while still allowing an application to access the object. If you need the object, you can still obtain a strong reference to it and prevent it from being collected.

How to use weak reference in c#?

Programming weak reference in C# The following code snippet shows how you can create a weak reference to an object. Rectangle rectangle = new Rectangle(15, 10); var weakReference = new WeakReference(rectangle); You can use the IsAlive property to check if the weak reference to the object is still alive.


1 Answers

I think the problem is in your test - not in the framework. It appears that setting the local variable to null doesn't do what you're expecting. If we skip the local variable entirely, we get the expected NullReferenceException on the 'after' line:

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();
}
like image 195
Av Pinzur Avatar answered Sep 30 '22 18:09

Av Pinzur