Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

precautions to take to prevent memory leaks due to added event handles

I am going to make a GUI that will have dynamically created sets of controls with events assigned to them. I will need to add and remove those controls at runtime. It will look like this:

FlowLayoutPanel.Controls.Clear();
<< add new controls, assigning Click events with += >>

I have heard that assigning event handlers with += can cause memory leaks (more specificly, memory will not be freed until application has exited). I want to avoid this. I know i can write some functions like here How to remove all event handlers from a control to find all event handlers and remove them but it looks very complex.

Is there another way? Does calling Dispose help remove those event handlers? Can you destroy objects to force their memory to be freed like in C/C++?

Thanks!

PS: Problem is, i dont know what event to detach. I will create lots of labels and add different kinds of onclick events to them. When its time to clean the flow layout panel, there is no way to know what event handler was attached to which label.

This is the example code (_flowLP is a FlowLayoutPanel) - this Refresh() function is ran multiple times before the application exits.

    private void Refresh()
    {
        Label l;
        Random rnd = new Random();

        // What code should i add here to prevent memory leaks
        _flowLP.Controls.Clear();

        l = new Label();
        l.Text = "1";
        if (rnd.Next(3) == 0) l.Click += Method1;
        if (rnd.Next(3) == 0) l.Click += Method2;
        if (rnd.Next(3) == 0) l.Click += Method3;
        _flowLP.Controls.Add(l);

        l = new Label();
        l.Text = "2";
        if (rnd.Next(3) == 0) l.Click += Method1;
        if (rnd.Next(3) == 0) l.Click += Method2;
        if (rnd.Next(3) == 0) l.Click += Method3;
        _flowLP.Controls.Add(l);

        l = new Label();
        l.Text = "3";
        if (rnd.Next(3) == 0) l.Click += Method1;
        if (rnd.Next(3) == 0) l.Click += Method2;
        if (rnd.Next(3) == 0) l.Click += Method3;
        _flowLP.Controls.Add(l);

        l = new Label();
        l.Text = "4";
        if (rnd.Next(3) == 0) l.Click += Method1;
        if (rnd.Next(3) == 0) l.Click += Method2;
        if (rnd.Next(3) == 0) l.Click += Method3;
        _flowLP.Controls.Add(l);

        l = new Label();
        l.Text = "5";
        if (rnd.Next(3) == 0) l.Click += Method1;
        if (rnd.Next(3) == 0) l.Click += Method2;
        if (rnd.Next(3) == 0) l.Click += Method3;
        _flowLP.Controls.Add(l);

        l = new Label();
        l.Text = "6";
        if (rnd.Next(3) == 0) l.Click += Method1;
        if (rnd.Next(3) == 0) l.Click += Method2;
        if (rnd.Next(3) == 0) l.Click += Method3;
        _flowLP.Controls.Add(l);
    }
like image 745
Istrebitel Avatar asked Apr 09 '12 18:04

Istrebitel


1 Answers

This is mainly going to be a worry when you attach a shorter lived event consumer to a longer lived event producer. If they have similar lives or are the opposite of what I described, it's a non-issue.

In the case where you do worry about this, just use -= to detach from the event. That removes the reference created by attachment and helps avoid this type of memory issue.

Edit: Since the comments are getting a little long, I'll post some follow up here. When you attach to an event, what you're doing is hanging a reference to yourself on the event provider. So, for instance, if you had a Clock class with a StrikesMidnight event and you subscribe to that event from a class called Bedtime, the actual mechanics of Bedtime saying clock.StrikesMidnight += this.HandleMidnight; is that you're assigning clock a reference to yourself. It's as if Clock had an object property and you said clock.ObjectProperty = this;

So, in a case where the Bedtime class is short-lived and goes out of scope, Bedtime shows up, hangs a reference to itself on Clock, and then goes out of scope. Problem is, Clock still has a reference to it, so even though it's out of scope, Garbage Collector won't collect Bedtime.

....

That's the background. In your case, you're creating a label and attaching a reference to yourself to it (via your "MethodX" handlers). When refresh is called, you clear your list of labels (meaning they go out of scope). They go out of scope and they have references to your class via its MethodX handlers, but so what? Them having references does not prevent them from being GC'ed. Nobody is holding references to them in your code, so the GC will do its work on them and you won't leak memory.

like image 80
Erik Dietrich Avatar answered Nov 15 '22 04:11

Erik Dietrich