I have this code:
Essentially i'm trying to demonstrate the use of the c# finalizer and make an object that cannot die, I called it Zombie. Now, normally this demo works great, but today I tried using the same code with the object initializer instead of just assigning to the property (Name in this case). I noticed there is a difference. Namely that the finalizer never gets called, not even when I'm trying my best to make the Garbage Collector do it's work.
Could someone explain the difference, or have I found a bug in the C# compiler?
(I'm using C# 4 in VS2010 SP1 on Win7x64)
Thanks.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace Zombie
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Main thread: " + Thread.CurrentThread.ManagedThreadId);
// case 1: this is where the problem is located.
Zombie z = new Zombie { Name = "Guy" }; // object initializer syntax makes that the finalizer is not called.
// case 2: this is not causing a problem. The finalizer gets called.
//Zombie z = new Zombie();
//z.Name = "Guy";
WeakReference weakZombieGuyRef = new WeakReference(z, true);
z = null;
GC.GetTotalMemory(forceFullCollection: true);
GC.Collect();
while (true)
{
Console.ReadKey();
if (weakZombieGuyRef.IsAlive)
{
Console.WriteLine("zombie guy still alive");
}
else
{
Console.WriteLine("Zombie guy died.. silver bullet anyone?");
}
Zombie.Instance = null;
GC.AddMemoryPressure(12400000);
GC.GetTotalMemory(forceFullCollection: true);
GC.Collect();
}
}
}
public class Zombie
{
public string Name { get; set; }
public static Zombie Instance = null;
~Zombie()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Finalizer called on zombie" + this.Name);
lock (typeof(Zombie))
{
Instance = this;
GC.ReRegisterForFinalize(this);
}
}
}
}
GC
will not collectz
(that is the objectz
originally referenced) before the method has ended. That's for easier debugging; it won't collect until local variable is out of scope in a formal way (z
is still in scope near the end of the method). If you extract the first part ofMain
(withz
) out to a separate method, it will work under Debug build as well. – Latterly