It is my understanding that after all strong references to the Target
of a WeakReference
are set to null and the GC is invoked, that weak reference should no longer be alive.
However, the code below does not appear to follow this expectation:
static void Main(string[] _) {
var person = new Person();
var wr = new WeakReference(person);
person = null;
// We should have access to the person here
if (wr.Target is Person shouldExist)
{
Console.WriteLine($"Person exists! IsAlive: {wr.IsAlive}.");
shouldExist = null;
}
else
{
Console.WriteLine($"Person does not exist :( IsAlive: {wr.IsAlive}.");
}
// Invoke GC.Collect.
GC.Collect();
if (wr.Target is Person shouldNotExist)
{
Console.WriteLine("This person should have been garbage collected");
Console.WriteLine($"IsAlive: {wr.IsAlive}");
}
else
{
Console.WriteLine("This person was garbage collected and weak reference is no longer alive");
Console.WriteLine($"IsAlive: {wr.IsAlive}");
}
}
where
class Person
{
private int mI = 3;
public int MI { get => mI; set => mI = value; }
}
And the output is
Person exists! IsAlive: True. This person should have been garbage collected IsAlive: True
I was expecting the output to be:
Person exists! IsAlive: True. This person was garbage collected and weak reference is no longer alive IsAlive: False
Am I missing something here about how weak references work?
The use of the references to the Person
object in Main()
is keeping the object alive until the end of the method.
If you change the code as follows (so that the access to the Person
object is in a separate method), it will work as expected in C# 12/.NET 8:
public static class Program
{
static void Main()
{
var wr = getWeakReference();
checkPersonExists(wr);
GC.Collect();
if (wr.Target is Person shouldNotExist)
{
Console.WriteLine("This person should have been garbage collected");
Console.WriteLine($"IsAlive: {wr.IsAlive}");
}
else
{
Console.WriteLine("This person was garbage collected and weak reference is no longer alive");
Console.WriteLine($"IsAlive: {wr.IsAlive}");
}
}
static WeakReference getWeakReference()
{
var person = new Person();
var wr = new WeakReference(person);
return wr;
}
static void checkPersonExists(WeakReference wr)
{
// We should have access to the person here
if (wr.Target is Person)
{
Console.WriteLine($"Person exists! IsAlive: {wr.IsAlive}.");
}
else
{
Console.WriteLine($"Person does not exist :( IsAlive: {wr.IsAlive}.");
}
}
}
class Person
{
private int mI = 3;
public int MI { get => mI; set => mI = value; }
}
NOTE: This behaviour is not guaranteed and may vary in different versions of C#/.NET.