Although Microsoft will claim that it is "not possible to have a memory leak in managed code", most seasoned .NET developers will laugh at that statement. It turns out that it is very easy to leak memory — just keep a referencing object around longer than the referenced object, and you can leak. There at least two tools on the market that are designed specifically to seek out memory leaks of this kind (Scitech and ANTS).
The most common case of this happens with events in C#. Take the following example:
In this example, the Observer class will hook the event on the Observable class during construction. Because of the way that events work in C#, the Observable object has a reference to the Observer. In the following example, the Observer will be alive (at least) as long as the Observable class is alive. For this reason, the following method will cause a memory leak:
In most cases, the Observer instance would be garbage collected as it went out of scope. Instead, since it is kept alive through the event handler of the Observable, we leak memory.
There is a pretty easy way to solve this. Simply unhook the event in the disposal event (actual "Dispose Pattern" removed for brevity).
Great! Now, as long as we dispose the Observer, all references will be removed and the object will get garbage collected. Unfortunately, it is VERY easy to forget to call the Dispose method. I want to write some tests to make sure that these objects are garbage collected.
This is a tall order to fill. Having a reference to the object will cause it to stay alive. How do you ask an object if it is alive without actually having a reference to the object? This is where the WeakReference class comes in. It is a magical class that keeps a reference to an object without the garbage collector knowing about the reference. I wrote the following class to help me monitor and test if it still alive:
Here are two examples of tests that illustrate the use of LeakMonitor. These are over-simplified unit test examples for this blog post, but you can see how this can be extended to integration and functional tests to verify that inner objects are not leaked. Be creative!