Andy's observations as he continues to attempt to know all that is .NET...

Wednesday, July 30, 2008

Weak Observer

During a recent teach of Code Smarter for Design Patterns in .NET  in which we teach the Observer pattern showing both traditional GOF implementation as well as a more appropriate .NET version using events.  One student after class told me he has never been keen on encouraging the use of event subscriptions as he was never confident that his developers would remember to unsubscribe from events when they no longer needed them.  This is in fact has been a common problem in .NET code that can often induce a memory leak.

The typical case that is often presented is one where a Windows Form subscribes to an event from a different object say some application object.  When the form subscribes to the event on the application object, the application object therefore has  a strong reference to the form so that it can deliver the events.  When the form is closed a failure to unsubscribe from the event means that there will still be a strong reference the form that will ultimately prevent it from being gc'd.  If this form has a large data table bound to a data grid this could have seriously impact on available memory during the applications life, as this data set will also not be gc'd

Clearly the right thing is for all programmers to remember to unsubscribe, but we know that often programmers forget and these leaks often go unnoticed until a customer screams.  An alternative would be for the application object not to hold  a reference and thus will not stop the window from being garbage collected, the obvious problem then is how can it deliver the event.  There is though a half way house through the use of a Weak Reference.  A Weak reference provides a means to reference an object without preventing it from being GC'd, but still allowing you to get to it whilst the GC'd hasn't decided to remove it.

As I said at the start we provide two implementations of the observer pattern one using interfaces, IObserver/IListener the other using .NET events.  Implementing a version of the observer pattern using the interface approach combined with Weak references is relatively trivial extension to the standard observer pattern.  The subject does not hold on to the observer/listener using a strong reference it is simply held as a weak reference. When the subject wishes to inform the observers of an event it walks through its list of weak refrerences turning each one into a strong reference for the duration of the notification.  If it fails to turn a weak reference into a strong reference it knows the observer has been gc'd.

When attempting to implement this behaviour using events things get a little bit more involved as the delegate chain holds the reference to the observer as a normal strong reference, that is something we can't change.  This is a shame since we would clearly love to have the choice to hold on to it as a weak reference, thus giving us a similar solution to Weak Observer.  In order to give an event style api we will need to be a bit more cunning, and also take a performance hit.  What I have done here is to continue to have the normal event subscribe/unsubscribe using a delegate, but then crack open the delegate to reveal the target instance and target method.  Once I have the target method and instance I wrap the instance up in a weak reference wrapped up by what I call a WeakEventHandle. After the construction of the handle it is placed into a handle list. When asked to fire the event each of the handles is visited in turn and the target method is invoked via reflection.  Invoking the method via reflection is not optimal in terms of performance and limits the possibilities of running the application with  reduced permissions .

private WeakEventMgr<SomeEventArgs> someEvent = new WeakEventMgr<SomeEventArgs>();

public event EventHandler<SomeEventArgs> SomeEvent
{
       add { someEvent.Add(value); }
       remove {someEvent.Remove(value); }
}

// .....

protected virtual void OnSomeEvent(SomeEventArgs someEventArgs)
{
  someEvent.Notify(this, someEventArgs);
}

Above is the code necessary to expose a WeakEvent, each event has its own instance of WeakEventMgr<T>.  The event subscribe/unscribe method is explicitly implemented to use WeakEventMgr as the backing store for the subscribers.  Finally to maintain the Microsoft pattern for event dispatch a virtual protected method exists to dispatch the event.  To make adding weak events easier I created a snippet. 

Using one of the implementations of Weak Observer means there is now less need to worry about ensuring that all subscribers have unregistered, since event subscriptions will not keep an object alive.

You can download the code here.  The code demonstrates the classic problem of form leakage.

No comments:

About Me

My photo
Im a freelance consultant for .NET based technology. My last real job, was at Cisco System were I was a lead architect for Cisco's identity solutions. I arrived at Cisco via aquisition and prior to that worked in small startups. The startup culture is what appeals to me, and thats why I finally left Cisco after seven years.....I now filll my time through a combination of consultancy and teaching for Developmentor...and working on insane startups that nobody with an ounce of sense would look twice at...