Weak Event Pattern and Memory Leak in .Net 4.5

One of the common issues with events and event handlers is memory leaks. In applications, it is possible that handlers attached to event sources will not be destroyed if we forget to unregister the handlers from the event. This situation can lead to memory leaks. .Net 4.5 introduces a weak event pattern that can be used to address this issue.

Problem: Without using weak event pattern.

Let's understand the problem with an example. If we understand the problem then the solution is very easy.

  1. public class EventSource  
  2. {  
  3.         public event EventHandler<EventArgs> Event = delegate { };  
  4.   
  5.         public void Raise()  
  6.         {  
  7.             Event(this, EventArgs.Empty);  
  8.         }          
  9. }  
  10.   
  11.   
  12. public class EventListener   
  13. {  
  14.         public int Counter { getset; }  
  15.         EventSource eventSourceObject;  
  16.   
  17.         public EventListener(EventSource source)  
  18.         {  
  19.             eventSourceObject= source;  
  20.             eventSourceObject.Event += MyHandler;  
  21.         }     
  22.       
  23.         private void MyHandler(object source, EventArgs args)  
  24.         {  
  25.             Counter++;  
  26.             Console.WriteLine("MyHandler received event "+ Counter);  
  27.         }  
  28.   
  29.         public void UnRegisterEvent()  
  30.         {  
  31.             eventSourceObject.Event -= MyHandler;  
  32.         }  
  33. }  
  34. static void Main(string[] args)  
  35. {              
  36.          EventSource source = new EventSource();  
  37.          EventListener listener = new EventListener(source);  
  38.          Console.WriteLine("Raise event first time");  
  39.          Console.Read();  
  40.          source.Raise();  
  41.   
  42.          //Set listener to null and call GC to release the  
  43.         //listener object from memory.  
  44.   
  45.          Console.WriteLine("\nSet listener to null and call GC");  
  46.          Console.Read();  
  47.         //developer forget to unregister the event               
  48.   
  49.         //listener.UnRegisterEvent();  
  50.          listener = null;  
  51.          GC.Collect();  
  52.          Console.WriteLine("\nRaise event 2nd time");  
  53.          Console.Read();  
  54.          source.Raise();  
  55.          Console.ReadKey();                  

Output



The developer is expecting that set listener = null is sufficient to release the object but this is not the case. The event listener object is still in memory.

the EventListener's handler should be called a second time. But it's calling.

In this example the developer forget to unregister the event. With this mistake, the listener object is not released from memory and it's still active. If we call the unregister method then the EventListener would be released from memory. But the developer does not remember when to unregister the event.

This is the problem!

Solution: Weak event pattern.

The weak event pattern is designed to solve this memory leak problem. The weak event pattern can be used whenever a listener needs to register for an event, but the listener does not explicitly know when to unregister.

In the old way of attaching the event with a source it is tightly coupled.

  1. eventSourceObject.Event += MyHandler; 

Using Weak event pattern

Replace the preceding registration with the following code and run the program.

  1. WeakEventManager<EventSource, EventArgs>.AddHandler(source, "Event", MyHandler); 



After raising the event a second time, the listener is doing nothing. It means the listener is no longer in memory.

Now the developer need not be concerned about calling the unregister event.

For any specific scenario if we want to unregister the event then we can use the RemoveHandler method as in the following:

  1. WeakEventManager<EventSource, EventArgs>. RemoveHandler(source, "Event", MyHandler); 

Up Next
    Ebook Download
    View all
    Learn
    View all