I want some Moore

Blog about stuff and things and stuff. Mostly about SQL server and .Net
posts - 219, comments - 2287, trackbacks - 33

My Links

Advertisement

News

Hi! My name is 
Mladen Prajdić  I'm from Slovenia and I'm currently working as a .Net (C#) and SQL Server developer.

I also speak at local user group meetings and conferences like SQLBits and NT Conference
Welcome to my blog.
SQL Server MVP

My Books

SQL Server MVP Deep Dives 2
The Red Gate Guide to SQL Server Team based Development Free e-book

My Blog Feed via Email
Follow MladenPrajdic on Twitter


Users Online: who's online

Article Categories

Archives

Post Categories

Cool software

Other Blogs

Other stuff

SQL stuff

C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

UPDATE:
After i've been proven wrong in the comments below I have to say this:

Go take a read of this article to see how circular references are really handled.

While Delegate.GetInvocationList() really is a great and usefull thing and it could be used in clearing up events,

there's no need for it since you can do that as easily by simply unsubscribin from the event when

you want to dispose your class.

 

You can read this post on,  but know that this example is WRONG, except for the last part about

Observer pattern and WeakEvent pattern.

Maybe you should read this post since sometimes you can learn how stuff works by reading how it doesn't work :))

---------------------------------------------------------------------------------------------------------------------------------------

Subscribed events are one of the most common reasons of memory leaks in .Net. This means that if you have an object that has an event

and there are other object that are subscribed to that event, the original object won't be properly disposed until all events are unsubscribed since

an event is a strong reference.

 

A simple example of this is a form called MyForm that has a public event called OnDoMyFormThing and 5 classes are subscribed to this event.

When the OnDoMyFormThing is executed on the form it will notify all 5 classes. You might call this event a few more times depending on what your form does. 

After this the form is closed. However the form isn't disposed until all 5 classes that are subscribed to the event get disposed. A hard way of doing this

would be to somehow implement the event removal on all 5 classes.

 

An easy way would be to do this in the Dispose method of the form itself. But how, if you don't know the name of every event handler.

But remeber that an event is just a delegate. And delegates have a GetInvocationList() method.

GetInvocationList() gets an array of delegates. Each delegate represents a method subscribed to an event. The order of the delgates is the same as the

invocation order of the subscribed methods on the event.

 

So your code in MyForm would be: 

 public partial class MyForm : Form
 {    
    public event EventHandler OnDoMyFormThing;
    
    public MyForm()
    {
        InitializeComponent();        
    }
    
    private void button1_OnClick
    {
        MessageBox.Show("Test of OnDoMyFormThing event");
        OnDoMyFormThing(this, new EventArgs());
    }
    
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            foreach (EventHandler eventDelegate in OnDoMyFormThing.GetInvocationList())
                OnDoMyFormThing -= eventDelegate;
            components.Dispose();
        }
        base.Dispose(disposing);
    }
}

 

And with this your form can be disposed normally.

 

Event subscriptions in 5 classes look like this: 

class1.MyForm.OnDoMyFormThing += Class1EventHandler
class2.MyForm.OnDoMyFormThing += Class2EventHandler
class3.MyForm.OnDoMyFormThing += Class3EventHandler
class4.MyForm.OnDoMyFormThing += Class4EventHandler
class5.MyForm.OnDoMyFormThing += Class5EventHandler

 

The strong bidirectional reference between an event and its subscriptions is a common problem in all Observer pattern scenarions, so you must

know about it and care about it. If not, you're sure to get memory leaks.

 

In .Net ramework 3.0 there is a pattern called WeakEvent that you can use to create a weak reference to events and not really care about disposal.

kick it on DotNetKicks.com
 

 

Print | posted on Wednesday, October 24, 2007 8:30 PM | Filed Under [ .Net ]

Feedback

Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

Does this mean that the CLR GC doesn't finalize the memory references to the form after the application terminates? Or is this only concerning the disposal during the execution of the application?
10/24/2007 8:55 PM | Frank Rau
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

no. yes. :)

when the application terminates the whole AppDomain is unloaded and closed. this means that its memory gets returned to the system.
10/24/2007 9:04 PM | Mladen
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

Seems you are wrong.

Subscribing to event increases lifetime of listented but not of the source object. and here is quote from msdn:

...
For instance, in C#, that syntax is: source.SomeEvent += new SomeEventHandler(MyEventHandler).

This technique creates a strong reference from the event source to the event listener. Ordinarily, attaching an event handler for a listener causes the listener to have an object lifetime that influenced by the object lifetime for the source (unless the event handler is explicitly removed).
...
10/25/2007 3:04 PM | Sergio
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

could you please post a link to that msdn document you read?
10/25/2007 3:05 PM | Mladen
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

sure. WeakEvent :) http://msdn2.microsoft.com/en-us/library/aa970850.aspx
10/25/2007 3:07 PM | Sergio
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

hmm... i don't think i understand what you mean then.
where exactly am i wrong?
10/25/2007 3:08 PM | Mladen
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

You wrote:
...
This means that if you have an object that has an event and there are other object that are subscribed to that event, the original object won't be properly disposed until all events are unsubscribed since an event is a strong reference.
...

It is not original object wont be disposed but listener. so in example above:

source.SomeEvent += new EventHandler(listener.OnSomeEvent);

listener wont be disposed while source is alive. so if there are no reference to source it will be collected even it has listeners attached, but if no reference to listener and it is subscribed to some of source's event, it will NOT be collected until source is collected.
10/25/2007 3:17 PM | Sergio
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

emm... you do realize that the weak event pattern is not what i'm talking about here?
weak event pattern is a new thing in .net 3.0 to prevent bidirectional strong references.
10/25/2007 3:21 PM | Mladen
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

I realize. and i don't see bidi reference here. source keeps reference to listener. but listener doesn't keep reference for source in case of event subscription
10/25/2007 3:28 PM | Sergio
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

events are delegates. delegates are strong references.
the object that fires the event has a refernce to the object subscribed to that event via that delegate. so they both know about each other until the subscribed object unsubscribes form an event.

this is not a weak event pattern as far as i know.



10/25/2007 3:43 PM | Mladen
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

source over delegate has reference to listener - true;
listnener has no reference to source unless you have it with member variable
10/25/2007 4:04 PM | Sergio
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

source over delegate has reference to listener - true;
listnener has no reference to source unless you have it with member variable
10/25/2007 4:04 PM | Sergio
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

it does have a reference over that delegate.
maybe you should provide some code to let me realize your point easier.
i love to be proven wrong :)
10/25/2007 4:06 PM | Mladen
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

http://www.interact-sw.co.uk/iangblog/2004/07/07/circulareventrefs
10/25/2007 4:37 PM | Sergio
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

http://www.interact-sw.co.uk/iangblog/2004/07/07/circulareventrefs
10/25/2007 4:37 PM | Sergio
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

Very informative read, Sergio!
Thanx!
10/25/2007 4:56 PM | Mladen
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

You're welcome:)
10/25/2007 5:16 PM | Sergio
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

Hi Mladen,

Good post.

You wrote:
foreach (EventHandler eventDelegate in OnDoMyFormThing.GetInvocationList())
OnSearch -= eventDelegate;

What is OnSearch in the foreach loop? Could you be more specific?

Thanks.
10/25/2007 11:00 PM | eBug
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

whoops that's a typo... OnSearch should be OnDoMyFormThing.
i'll fix it.
10/25/2007 11:01 PM | Mladen
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

You've got the dependency order wrong as others have pointed out.

Moreover, you could also just set the event handler delegate to null instead of traversing the invocation list. In other words, just write: "OnDoMyFormThing = null".
10/26/2007 8:17 AM | Jeff Brown
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

yes. you're right. i'll fix that over the weekend.
10/26/2007 10:44 AM | Mladen
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

Mladen, you're just wrong about the circular references. Save yourself further embarrassment and just delete this blog post. Read Ian Griffiths' article and take comfort in the fact that aren't the first and won't be the last to misunderstand how the .NET GC works, or how circular references are handled in GC environments.

I'd also like to recommend a new problem solving approach for you in the future:

1. First show a simple example that demonstrates the problem that you claim exists (a form and the handler classes NOT being finalized by the GC when fully-dereferenced)
2. Show your supposed fix

If you're going to skip step 1, at least realize that if your solution to the Next Big Problem involves everyone in the world adding code to common classes to fix what you see as a fundamental problem that nobody else has reported, maybe you should take a closer look at how you're writing code to make sure it's not just something you're doing wrong. I guarantee this will save face in the future.

Good luck,

JD
10/27/2007 10:02 AM | JD
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

yes i know i'm wrong. i thought we came to that conclusion with Sergio already.
thank you for pointing it out :)))

There's no need to save my face, since i'm not the first person to be wrong, right?
For me the main thing is to learn something new which i have.
and no i won't delete the post. i'll just update it with the correct information,
when i came around to itl
10/27/2007 4:18 PM | Mladen
Gravatar

# c# programming from a to z

Hey

Could you please help me out to find a book which contains the programming basics of C#? The book which can be followed in lab experiments ( from beginners to advanced).
The book which can tell you how to give inputs through console; be it an array, a string or a single character.
11/16/2007 6:34 AM | shantanu sinha
Gravatar

# re: C#: Care about Event Memory Leaks with Delegate.GetInvocationList()

why not just find/replace and do a search for += new in all open documents, then copy paste all event handlers into notepad then paste them into your dispose() method in the .cs designer and replace + with - ?

Sure that would be alot easyier and time consuming than trying to fix something that isnt broken?

Regards

Dean
4/22/2009 5:31 PM | Dean
Gravatar

# Thanks

Thank you for keeping this wrong blog post open as the ensuing discussion is very important. The author, by solving a problem that doesn't exist helps to solve a wider problem of misunderstanding in this area.
4/2/2010 7:59 PM | Luke Puplett
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET