views:

1093

answers:

2

This is a WinForm MDI application problem (.net framework 3.0). It will be described in C#. Sorry it is a bit long because I try to make things as clear as possible.

I have a MDI application. At some point I find that one MDI child form is never released. There is a menu that creates the MDI child form and show it. When the MDI child form is closed, it is supposed to be destroyed and the memory taken by it should be given back to .net. But to my surprise, this is not true. All the MDI child form instances are kept in memory. This is obviously a "memory leak". Well, it is not a real leak in .net. It is just that I think the closed form should be dead but somehow there is at least one unknown reference from outside world that still connect with the closed form.

I read some articles on the Web. Some says that when the MDI child form is closing, I should unwire all the event handlers, otherwise some event handlers may keep my form alive. Some says that DataBindings should be cleaned before the form is closing otherwise the DataBindings will add references to some global Hashtable and thus keep my form alive.

My form contains quite a lot things. Many event handlers and many DataBindings and many BindingSources and few suspected controls containing user control and HelpProvider. I create a big method that unwires all the event handlers from all the relevant controls, clear all the DataBindings and DataSources. The HelpProvider and user controls are disposed carefully.

At the end, I find that, I don't have to clear DataBindings and DataSources. Event handlers are definitely causing the problem. And MDI form structure also contributes to something.

During my experiments, I find that, if you create a MDI child form, even if you close it, there will still be one instance in the memory. The reference is from PropertyStore of the main form. This means, unless the main form is closed (application ends), there will always be one instance of MDI child form in the memory. The good news is that, no matter how many times you open and close the child form, there will be only one instance, not a big "leak".

When it comes to event handlers, things become more tricky. I have to address that, all the event handlers on my form are anonymous event handlers. Here is an example code:

//On MDI child form's design code...

Button btnSave = new Button();

btnSave.Click += new System.EventHandler(btnSave_Click);

Where btnSave_Click is also a method in MDI child form. The above is always the case for various controls and various types of event. To me, this is a bi-directional circular reference. btnSave keeps a reference of MDI child form via the event handler. MDI child form keeps a reference of btnSave instance. To me again, such bi-directional circular reference should not cause any problem for .net's garbage collector. This means that I do not have to explicitly unwire the event when the form is being disposed:

btnSave.Click -= btnSave_Click;

But the truth is not so. For some event handlers, they are safe. Ignoring them do not cause any duplicate instance. For some other event handlers, they will cause one instance remaining in the memory (similar effect as the MDI form structure, but this time caused by the hanging event handlers). For some other event handlers, they will cause every instance opened in the memory. I am totally confused about the differences between these three types of event handlers. The controls are created in the same way and the event is attached in the same way. What is the difference? (Don't tell me it is the event handle methods that make difference.) Anyone has experience of this wired scenario and has an answer for me? Thanks a lot.

So now, for safety issue, I will have to unwire all the event handlers when the form is being disposed. That will be a long list of similar code for each control. Is there a general way of removing events from controls in recursive way using reflection? What about performance issue?

That's the end of my story and I am still in the middle of my problem. For any help, I thank you.

A: 

As long as the object that the event handler is wired to is declared in the child form you don´t have to remove the event handler when the child form is disposed, but when the object that the event handler is wired to is declared outside the child form you must remove the event handler when the child form is disposed.

If this code is executed several times (and btnSave is an object not declared in the child form)

btnSave.Click += btnSave_Click;

This code has to be executed the same number of times

btnSave.Click -= btnSave_Click;


It might be that you are referencing the child form somewhere in the application, this reference must be removed before the garbage collector will remove the child form object.

Jens Granlund
A: 

Your problem can be solved by the solution offered here.

George Stocker