Events and Resouce Leak

 

Had this question when I was reading “Effective C#: 50 Specific Ways to Improve Your C#”.

In the item 18: "Implement the Standard Dispose Pattern", the book recommends to implements IDisposable.Dispose() to do following tasks:

1.    Freeing all unmanaged resources.

2.    Freeing all managed resource (this includes unhooking events).

3.   

My question is on point 2, why do we have to unhook events?

After having a look of how System.Delegate is implemented, I found the reason is actually quite simple.

To answer the question, first let's have a look this program:

public class Publisher

{

    public event EventHandler SomethingHappen;

}

 

public class Subscriber

{

    public void DoSomething(object sender, EventArgs e)

    {

    }

}

 

public class Test

{

    public static void Main(string[] args)

    {

        Publisher publisher = new Publisher();

        Subscriber subscriber = new Subscriber();

        publisher.SomethingHappen += subscriber.DoSomething;

    }

}

 

The thing we need to take a good look is the last line of Main() method. In the Main(), there are three objects are created. Apart from a publisher, a subscriber created by the first and second line, the third line "publisher.SomethingHappen += subscriber.DoSomething" creates and an object as well.  The type of the object created is EventHandler which is derived from System.MulticastDelegate which, in turn, is derived from System.Delegate.

In System.Delegate, it maintains four private fields:

internal object _target;

internal IntPtr _methodPtr;

internal IntPtr _methodPtrAux;

internal MethodBase _methodBase;

 

Two fields are relevent here: _methodPtr and _target. In our program, the EventHandler object created will have its _target field points to subscriber object, and _methodPtr points to the memory address of DoSomething() method. A delegate must have _target field because to invoke an instance method, the first parameter is passed to the method has to be method's "this" pointer. So when a delegate object wraps an instance method, the delegate must maintain the "this" pointer, in another word, to invoke an instance method, a delegate must know the instance. If a delegate object wraps a static method, then _target will be set to null.

 

The answer to the question is quite clear now: as long as the publisher object is alive, subscriber object will be always referenced by the delegate object, it will not be able to get garbage collected even we explicitly set subscriber = null. So if we don't unhook event, it is likely to introduce a resource leak.

 

As a proof of concept, let's run this little program:

public class Publisher

{

    public event EventHandler SomethingHappen;

}

 

public class Subscriber

{

    private int[] array = new int[1000000];

    public void DoSomething(object sender, EventArgs e)

    {

    }

}

 

public class Test

{

    public static void Main(string[] args)

    {

        Publisher publisher = new Publisher();

        for (int i = 0; i < 10; i++)

        {

            Subscriber subscriber = new Subscriber();

            publisher.SomethingHappen += subscriber.DoSomething;

            //publisher.SomethingHappen -= subscriber.DoSomething;        

subscriber = null;

        }

        Console.WriteLine("Total memory allocated: " + GC.GetTotalMemory(true));

        Console.ReadKey();

    }

}

The first time I run it with the line for unhooking event commented off, the memory usage is: 40802720. Second time with the line turned on, the memory usage became only: 800948

 

Print | posted on Tuesday, February 20, 2007 4:08 PM

Feedback

# re: Events and Resouce Leak

Left by khan at 8/6/2017 3:43 AM
Gravatar Great coding thanks to admin for sharing with us and here i have Jachdi Song Lyrics which is the latest punjabi song.Thanks again for sharing.

Your comment:





 

Copyright © Changhong Fu

Design by Bartosz Brzezinski

Design by Phil Haack Based On A Design By Bartosz Brzezinski