C# Events and Garbage Collection
- December 15th, 2010
- Posted in Coding
- Write comment
A friend asked me earlier about garbage collection in C#. What happens to an object with Events when we set it to null, will the references in the event prevent it from being GCed?
Lets say we’ve got 2 classes, Listener and Generator. Generator has an event called SayMyName and each Listener registers to that event when it gets created.
Notice in the Listener class we dont actually store the Generator in a class level variable (or property). What links these two together is stored in the Generator reference to the Listener is added to the Generator
public class Listener
{
static List instances = new List();
public Listener(Generator generator)
{
instances.Add(new WeakReference(this));
generator.SayMyName += new Generator.SayMyNameHandler(Generator_MyEvent);
}
void Generator_MyEvent(string name)
{
Console.WriteLine(name);
}
public static void TestReferences()
{
int cnt = 0;
foreach (WeakReference instance in instances)
{
Console.WriteLine("Instance " + (cnt++) + " is " + (instance.IsAlive ? " alive " : " gone"));
}
}
}
Now for the Generator class, we’re going to do something a bit special. We’re going to create a static List of WeakReferences to keep track of the instances and whether they’ve actually been disposed of by the Garbage Collector. WeakReferences are ignored when counting references on an object during garbage collection.
public class Generator
{
static List instances = new List();
private string _name = null;
public string Name {
get
{
return _name;
}
set
{
_name = value;
OnSayMyName();
}
}
public event SayMyNameHandler SayMyName;
public delegate void SayMyNameHandler(string name);
public Generator()
{
instances.Add(new WeakReference(this));
}
protected void OnSayMyName()
{
if (SayMyName != null)
SayMyName(Name);
}
public static void TestReferences()
{
int cnt = 0;
foreach (WeakReference instance in instances)
{
Console.WriteLine("Instance " + (cnt++) + " is " + (instance.IsAlive ? " alive " : " gone"));
}
}
}
Now lets try actually making use of these, then try to remove our Generator.
Generator generator = new Generator();
Listener listener = new Listener(generator);
Console.WriteLine("Generator References:");
Generator.TestReferences();
Console.WriteLine("Listener References:");
Listener.TestReferences();
generator = null;
GC.WaitForFullGCComplete();
//No Generator instances will remain, Listener has no reference to Generator
Console.WriteLine("Generator References:");
Generator.TestReferences();
Console.WriteLine("Listener References:");
Listener.TestReferences();
Alternatively, the same cannot be said if we want to get rid of a Listener so easily.
Generator generator = new Generator();
Listener listener = new Listener(generator);
Console.WriteLine("Generator References:");
Generator.TestReferences();
Console.WriteLine("Listener References:");
Listener.TestReferences();
listener = null;
GC.WaitForFullGCComplete();
//Listener instance remains because the reference is held by the Event.
Console.WriteLine("Generator References:");
Generator.TestReferences();
Console.WriteLine("Listener References:");
Listener.TestReferences();

No comments yet.