Let's consider following simple program:
class Program
{
class TestClass
{
~TestClass()
{
Console.WriteLine("~TestClass()");
}
}
static void Main(string[] args)
{
WeakReference weakRef;
{
var obj = new TestClass();
weakRef = new WeakReference(obj);
Console.WriteLine("Leaving the block");
}
Console.WriteLine("GC.Collect()");
GC.Collect();
System.Threading.Thread.Sleep(1000);
Console.WriteLine("weakRef.IsAlive == {0}", weakRef.IsAlive);
Console.WriteLine("Leaving the program");
}
}
When built in Release mode, it predictably prints:
Leaving the block
GC.Collect()
~TestClass()
weakRef.IsAlive == False
Leaving the program
When Debug version is launched (not under the Debugger, usual launch from Windows Explorer), the output differs:
Leaving the block
GC.Collect()
weakRef.IsAlive == True
Leaving the program
~TestClass()
Running under the debugger for both versions doesn't change the output.
I've discovered this strange difference during debugging of my custom collection that keeps weak references to objects.
Why garbage collector in debug executables does not collect objects that clearly are not referenced?
UPDATE:
Situation differs if object creation is performed in other method:
class Program
{
class TestClass
{
~TestClass()
{
Console.WriteLine("~TestClass()");
}
}
static WeakReference TestFunc()
{
var obj = new TestClass();
WeakReference weakRef = new WeakReference(obj);
Console.WriteLine("Leaving the block");
return weakRef;
}
static void Main(string[] args)
{
var weakRef = TestFunc();
Console.WriteLine("GC.Collect()");
GC.Collect();
System.Threading.Thread.Sleep(1000);
Console.WriteLine("weakRef.IsAlive == {0}", weakRef.IsAlive);
Console.WriteLine("Leaving the program");
}
}
It outputs the same output in Release and Debug versions:
Leaving the block
GC.Collect()
~TestClass()
weakRef.IsAlive == False
Leaving the program