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:
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?
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.
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.
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.
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();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With