I have been trying to find the time write a post about event handler that causes memory leak. Finally I find the time to write something about.
.NET has Garbage Collect == No Memory Leaks?
Of course NOT. Even in the modern language like C#, we still have to worry about memory leak.
Possible Causes of Memory Leak
- Failed to close or clean up unmanaged code
- Created static object that isn’t being use after its first use
- Failed to dereference event handler in certain situation. (i.e. you did the += handler, but not the –= handler)
Why you need to do –= Event Handler?
This time, I want to explicitly talk about the important of dereference event handler. It is a common mistake that developers forget to do.
In most cases, you don’t usually need to perform dereference your event handler. For example:
1: public class Class1
2: {
3: private EventHandler SomeEvent;
4:
5: public Class1()
6: {
7: SomeEvent += SomeEventHandler;
8: }
9:
10: private void SomeEventHandler(object sender, EventArgs args)
11: {
12: // Some something
13: }
14: }
When Class1 is disposed, the entire class is disposed, therefore you don’t need to worry about dereferencing class1’s event handler.
However, if your event handler is attached to an external object, you should dereference your event handler when your class is disposed. For example, the following causes a memory leak:
1: namespace EventHandlerTest2
2: {
3: public class Program
4: {
5: public EventHandler SomeEvent;
6:
7: static void Main(string[] args)
8: {
9: Program program = new Program();
10: for(int i = 0; i < 10; i++)
11: program.Run();
12: }
13:
14: public Program()
15: {
16: CreateUselessHelper();
17: }
18:
19: public void Run()
20: {
21: if (SomeEvent != null)
22: SomeEvent(this, null);
23: }
24:
25: private void CreateUselessHelper()
26: {
27: //Create a Helper class locally,
28: //will this object stick around after this function exit?
29: HelperClass helperClass = new HelperClass(this);
30: }
31: }
32:
33: public class HelperClass
34: {
35: public HelperClass(Program program)
36: {
37: program.SomeEvent += SomeEventHandler;
38: }
39:
40: private void SomeEventHandler(object sender, EventArgs args)
41: {
42: Console.WriteLine("I am still around!");
43: }
44: }
45: }
In the above code, I created a HelperClass object in the CreateUslessHelper() method call. Typically, you would think that once this method is completed, the HelperClass is garbage collected. Unfortunately, in this case, it does not get garbage collected. When the HelperClass.SomeEventHandler attached to Program.SomeEvent, it causes the Program object to reference HelperClass. As a result, the Helper class will stick around until the Program object get garbage collected.
Solution
An appropriate way to clean up this event handler is simply implement IDispoble in the Helper Class. In the dispose method you simply dereference the event handler.
1: public class HelperClass: IDisposable
2: {
3: private Program _program;
4: public HelperClass(Program program)
5: {
6: _program = program
7: _program.SomeEvent += SomeEventHandler;
8: }
9:
10: private void SomeEventHandler(object sender, EventArgs args)
11: {
12: Console.WriteLine("I am still around!");
13: }
14:
15: public void Dispose()
16: {
17: _program.SomeEvent -= SomeEventHandler;
18: }
19: }
Here is a example that I wrote which demonstrates the effect of memory leak if event handlers are not dereferenced.
Memory Leak Example (This is my first time trying to use a file hosting service)