No more memory leakage, part I
When switching from C++ to C# one of the thing I was glad was gone was the need of always having to be aware of memory leaks caused by forgetting calling delete() and similar stuff.
During the development of the ByggOffice application, I soon found out that this was not completely true. Even in managed .Net code you still have to watch out for situations that will cause memory leaks.
Do we have memory leakage in .Net applications?
A very simple way to start leaking memory in a .Net windows application is to just do what almost all examples shows you to do to handle UI state:
protected override void OnLoad(EventArgs e) {
Application.Idle += new EventHandler(Application_Idle);
}
void Application_Idle(object sender, EventArgs e) {
// do some processing to check and update UI state
}
The tiny little detail that is let out here is that this will in effect add a reference from the form to the Application object. And as you probably would guess, the Application object will not go out of scope as long as your application is running.
This will cause the form to stay in memory as long as the application is running. And not only the form, but all objects that the form is referencing as well.
And this goes even if you call Close, Dispose or whatever you like on the form. As long as it’s holding on to that reference to the Application object, it will not be collected by the GC and it will not free the memory used.
In a real-life application this may very well mean that the form will consume several MB of memory each time it is shown. And each new instance of that form will consume the same memory all over again.
But can’t it be solved?
Yes, it can.
As listening to the Application.Idle event is actually a very useful way of updating the UI state you should still continue to use this method.
The fix for this issue is actually quite easy; just remove the event handler in the Dispose method of the form like this:
protected override void Dispose(bool disposing) {
Application.Idle -= new EventHandler(Application_Idle);
if (disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
The problem here is not to actually write the code, it’s to remember that you have to write the code and that this is not handled just because you are writing in a managed language.
And BTW: that other small issue:
Just thought I should mention this while I’m onto it.
Calling Close on a form shown using the ShowDialog() method will NOT dispose the form, and if the form is not disposed the Dispose method will not be called and the form will again be left in memory as long as the application is running.
This means that you have two options.
- Ensure that anyone using your form as a dialog calls it like this:
using(MyForm frm = new MyForm()){
frm.ShowDialog(this);
} - Move your event disconnection method to a different place, for example into the OnClosed method like this:
protected override void OnClosed(EventArgs e){
Application.Idle -= new EventHandler(Application_Idle);
}
In theory the user should be using the using() approach as it will ensure that the forms Dispose() method is called in all cases and that any nessesarly deallocation done by the form is called.
However, in the real life that is not how stuff is working and depending on others to do this is a long shoot that I would not recommend.
1 Comments:
This solution seems to be the way to go. This has gotten us past our deadlock issues.
Post a Comment
<< Home