9

I have a program which allows the editing of product information. I noticed that it was not releasing memory after closing the editing forms. After some research I stumbled upon this question which mentions that the problem may be that it is hanging on to event subscriptions.

That made sense to me because this form has about 100+ controls on it, many of which are custom with custom events which are subscribed to by their parent controls. This creates a pretty large hierarchy of event subscriptions. So I looked for a way to release these and found this which allows you to unsubscribe from that event.

The problem is, I have a ton of subscriptions. Do I really have to manually unsubscribe from each event one by one on form close, or is there at least a way to release them in one fell swoop, or loop through them?

Community
  • 1
  • 1
Nick
  • 1,903
  • 2
  • 21
  • 40

2 Answers2

6

Remember this: The object on the LEFT of the += keeps alive the object containing the method on the RIGHT of the +=. That is, the object that raises the event keeps alive the object that handles the event, even if the object (such as a form) that handles the event is disposed.

So the thing you need to ensure is that all the event-raisers have gone away.

However, if all the event-raisers happen to be controls in the same Form class that subscribes to those events, you will not need to manually unhook all the event handlers when the form is closed.

This is because the controls that raise the events to which to form has subscribed have the same lifetime as the form itself.

You only need to worry if you subscribe to events raised by an object that has a longer lifetime than the object that is subscribing. Then the subscribing object (the form) would need to unsubscribe when it (the form) is disposed.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • So in the situation: Form => Control1 => Control2, with each subscribing to events of those to it's right, as long as Control2 was gone first, the cascade should be fine and all events released properly? – Nick May 03 '13 at 15:20
  • @Nick Yes, if the form contains (directly or indirectly) both those controls, it should be fine. The controls will not be reachable from any live object once the form has been disposed - but that assumes that you don't have any references to the form anywhere! If you do, it won't matter if it's been disposed - it would still be reachable so in that case it would be still alive, along with all its controls. So it's pretty crucial that you don't have any non-null references to the form anywhere! – Matthew Watson May 03 '13 at 15:31
  • Ok, so in the case of a form being created and displayed within a menu item click event with no other references to that form. When that form closes, in theory, all of its child controls should be released as well as their respective events? – Nick May 03 '13 at 18:01
  • @Nick: Yep, it *should*. But the form *could* in theory obtain an external event and subscribe to it, or it could call an external object and pass "this" or a reference to one of its fields. There are so many ways that an object can wind up with something else holding a reference to it! You can only check by code inspection - check all the methods in the form and make sure it's not subscribing to external objects or passing "this" references to any external objects that might hang on to the refs. (Hopefully you see what I mean.) – Matthew Watson May 03 '13 at 18:19
  • @Nick: One more thing: At work we use [Redgate's ANTS Memory Profiler](http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/) There's a 14-day free trial, so you might be able to check things with that. It's excellent for finding "leaks" like this - but it does have a bit of a learning curve. Something to consider anyway. – Matthew Watson May 03 '13 at 18:26
  • Hmmm, I think I follow you. I definitely (read: really hope) don't do anything that would pass a reference to that form into something else. But let me ask you this. I hold a list of items in a (nHibernate) session that I use to bind an item into that form. Since that item stays alive past the context of that form, could that actually be causing the resources of the form to be maintained and not the the events? – Nick May 03 '13 at 18:30
  • @Nick *If* you passed or added to the nHibernate list a reference to your form or one of its fields, then it's possible that the list could be holding on to it. That ANTS memory profiler I mentioned will show you a graph of all current objects when you break in the debugger, so that could well help you find out for sure. – Matthew Watson May 03 '13 at 18:47
  • I'm checking it out now. Thanks for your time and all your help! – Nick May 03 '13 at 19:11
4

It depends on how long your form and its events will be living.

However, you can loop through your controls within the form, releasing the events. If you remove a nonexisting event accidentally - don't worry, it won't throw an exception.

For example, this is how to get rid of all your TextBox.KeyDown-Events:

  private void frm_FormClosed(object sender, FormClosedEventArgs e)
    {
    foreach (Control tb in this.Controls)
    {
        if (tb is TextBox)
        {
            TextBox tb1 = (TextBox)tb;
            tb1.KeyDown -= TextBox_KeyDown;
        }
    }
Fabian Bigler
  • 10,403
  • 6
  • 47
  • 70