The World’s Leading Microsoft .NET Magazine
   
 
The .NET Addict's Blog

My Top Tags

                                                           

My RSS Feeds








I heart FeedBurner

Latest Diggs - Programming

Computers Blogs - Blog Top Sites

Site Hits

Total: 4,896,068
since: 19 Jan 2005

Implementing the Weak Event Pattern in CLINQ v2.0

posted Mon 13 Oct 08

Before I get to talking about how CLINQ v2.0 is implementing the Weak Event Pattern, I want to discuss the problem that created the need for the Weak Event Pattern (WEP hereafter) in the first place.

When you add a listener to an event in .NET, you are creating a new instance of a delegate and adding it to the invocation list of the public event on the source object. This new delegate maintains a reference to the listening object through what is called a target. The target is a strong reference to an object, in our case it is a strong reference to the object containing the event handler that will be invoked whenever the event on the source object is fired. It's kind of a low-level description, but this kind of plumbing is something that most .NET developers are pretty familiar with, especially if they have done any serious GUI development. 

This is all fine and good for a majority of the circumstances under which CLINQ is going to be used, and in fact is fine for a large amount of other uses of events and event handlers in C#. However, there are some specialized cases where the lifetimes of the event source and the event listener are not bound to each other. In other words, if your application will be disposing of the event listeners at different times than the event sources (or, just as commonly, only one half of the symbiosis is ever disposed of entirely, leaving one partner dangling) - then you could be causing memory leaks without knowing it.

A classic example of this is where you have an event source and then an event subscriber. Let's say you have a WPF application and you have a bunch of code that fires in response to an event, and it's all encapsulated in an instance of GuiListener. Now let's say that you're done with GuiListener and it goes out of scope or you manually dispose of it. You think you've gotten rid of it, but because C# hides you from the details of true finalization, you aren't actually told that a GC pass failed to collect your object. 

Why did your GuiListener object fail to be disposed and not get collected? The problem starts with how the GC figures out what can and cannot be collected. Picture an in-memory graph that shows the reference connectivity between all managed objects on the heap. When the GC does a pass (oversimplification here..but bear with me), it traverses the tree of reference connections. If an object exists on the managed heap that cannot be reached (zero paths) on the root traversal tree, then the GC figures that nobody is using that object and it's safe to dispose of the memory associated with that object.

This is where the problem shows up: When a new instance of the delegate has been created with it's target property set to your GuiListener object, your object will NEVER have 0 references to it, and so will NEVER be reclaimed by the GC. Now imagine that this isn't a long-lived object, but one that is instantiated long enough to accomplish a task and then disposed. Each time this task is performed, your application is effectively hemorrhaging heap space.

To fix this, we use a Weak Event Pattern. What this really means is that there is no strong reference between the event source and the event listener. Both the source and the target can be disposed of independently of each other and the delegate linking the two of them will go away through some clever use of scope and some built-in .NET handy classes.

.NET gives us a ready-made, ready-to-customize implementation of weak event management through the EventManager classes. We make heavy use of one of these in particular, the CollectionChangedEventManager. This class not only provides a weak event handler, but also provides a central location for event management, further faciltating a loosely coupled design. CLINQ v1.x used a custom implementation of the WEP, but CLINQ v2.0 uses the weak event support supplied by the .NET Framework itself and has, so far, been working flawlessly on top of it.

One could argue that you should just manually dispose your own delegates and do so in the right order so that you don't leak memory and so that you don't leave dangling references. This is true, and if you are building an application where you know exactly where all the endpoints are, you can do this. However, for something like CLINQ, where we don't know ahead of time how it will be consumed, by whom, or for what purpose, and when the collections will go out of scope... it is simply far easier to use the WEP. However, we do use strong event handlers when we are the ones in control of creating them and disposing them since strong event handlers perform faster than weak.

tags:            

links: digg this    del.icio.us    technorati    reddit

AddThis Social Bookmark Button




1. Fastcars left...
Thu 06 Nov 08 6:41 am

I am not sure you are right.

The GC will garbage collect most events handlers as most event delegates are instances associated for example with a specific control. The graph of classes associated with the controls event handler and the listener(the form in most instances) will not have a root reference for most forms. ie it will be closed directed graph .


Tag Related Posts

Smart, Deep Property Notifications in CLINQ v2.0

Tue 07 Oct 08 1:15 P GMT-05
tags:          

Microsoft's Lofty Direction

Sun 05 Oct 08 2:30 P GMT-05

MobileMe vs. Live Mesh Throwdown - Round 1

Wed 16 Jul 08 10:33 A GMT-05

Building Model Classes in C# and Cocoa

Sun 15 Jun 08 3:13 P GMT-05
tags:            

CLINQ v1.1.0.0 Released!

Fri 02 May 08 5:38 P GMT-05
tags:          

One Framework to Rule them All

Mon 25 Feb 08 6:49 P GMT-05

CLINQ v1 Demo - Network Message Filtering

Wed 09 Jan 08 7:47 P GMT-05
tags:        

Continuous LINQ v1.0.0.0 Released

Tue 08 Jan 08 4:53 P GMT-05

LINQ to REST - A much better name for Astoria

Tue 11 Dec 07 1:23 P GMT-05
tags:        

Unexpected and Unsafe behavior in LINQ

Wed 14 Nov 07 8:09 P GMT-05
tags:    

Building a Ledger Style for WPF Grids

Tue 21 Aug 07 3:30 P GMT-05
tags:    

Continuous LINQ - Can I write games with it?

Mon 13 Aug 07 3:09 P GMT-05
tags:        

Continuous LINQ

Mon 06 Aug 07 1:21 P GMT-05
tags:    

Dynamic, Observable LINQ Views

Tue 31 Jul 07 1:21 A GMT-05
tags:        

The dreaded language bleed-over has begun

Tue 19 Jun 07 6:23 P GMT-05
tags:        

Installing Orcas Beta 1 - VMware Style

Mon 23 Apr 07 12:16 P GMT-05

My Little Pony .NET Unleashed 2007

Fri 30 Mar 07 1:59 P GMT-05

Authorness

Thu 15 Mar 07 1:44 P GMT-05

Visual Studio "Orcas" - March CTP is Available

Wed 28 Feb 07 12:28 P GMT-05
tags:            

Objective-C Categories vs C# 3.5 Language Extensions

Mon 26 Feb 07 1:05 P GMT-05
tags:                

Localizing a WPF Application

Tue 22 Aug 06 11:39 A GMT-05
tags:            

Is Windows Workflow Foundation Too Complex?

Fri 18 Aug 06 12:15 P GMT-05

DLinq vs the ADO.NET Entity Framework

Fri 23 Jun 06 4:01 P GMT-05

WPF/XAML and LINQ - A match made in heaven

Tue 06 Jun 06 11:32 A GMT-05
tags:                  

Language Extensions in C# 3.0

Wed 31 May 06 2:17 P GMT-05

Lambda Lambda Lambda

Sun 21 May 06 1:01 A GMT-05

The Adventures of LINQ (Not Zelda)

Fri 19 May 06 11:21 P GMT-05
tags: