Friday, November 14, 2008
Blogger Site Retired
This is the last post on http://brian.genisio.org. I have recently joined the developer community GeeksWithBlogs for my blog. I haven't transferred the domain over since there are a lot of sites linking this blog and I don't want to break the links.
I was able to transfer my RSS feed, but if you are getting this post via RSS, then you will need to subscribe to my feedburner feed, and unsubscribe from this feed.
My new blog is: http://HouseOfBilz.com
My RSS feed: http://feeds.feedburner.com/genisio
Tuesday, November 11, 2008
Writing Tests to Catch Memory Leaks in .NET
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:
public class Observable
{
public delegate void SomethingHappenedDelegate();
public event SomethingHappenedDelegate SomethingHappened;
// Rest of the class
}
public class Observer
{
private readonly Observable _observable;
public Observer(Observable observable)
{
_observable = observable;
_observable.SomethingHappened += UhOh_SomethingHappened;
}
void UhOh_SomethingHappened()
{
// Handle the event
}
}
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:
public void LeakAnObserver()
{
var observer = new Observer(_observable);
}
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).
public class Observer : IDisposable
{
// Existing code
public void Dispose()
{
_observable.SomethingHappened -= UhOh_SomethingHappened;
}
}
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:
public class LeakMonitor<T>
{
private readonly WeakReference _reference;
public LeakMonitor(T itemToWatch)
{
_reference = new WeakReference(itemToWatch);
}
public bool ItemIsAlive()
{
GC.Collect();
GC.WaitForPendingFinalizers();
return _reference.IsAlive;
}
public T Item
{
get
{
return (T)_reference.Target;
}
}
}
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!
[TestFixture]
public class MemTests
{
private Observable _observable;
[SetUp]
public virtual void SetUp()
{
_observable = new Observable();
}
[Test]
public void Test_That_Observer_Leaks()
{
var monitor = new LeakMonitor<Observer>(LeakMemory());
Assert.That(monitor.ItemIsAlive(), Is.True);
}
[Test]
public void Test_That_Disposing_Observer_Does_Not_Leak()
{
var monitor = new LeakMonitor<Observer>(LeakMemory());
monitor.Item.Dispose();
Assert.That(monitor.ItemIsAlive(), Is.False);
}
private Observer LeakMemory()
{
return new Observer(_observable);
}
}
Friday, November 7, 2008
I will be speaking at GLUG.NET Lansing on November 20th, 2008. My topic will be a talk I have given once before -- Castle Active Record (Don't Get Good at a CRUDy Job). Thanks to Jeff McWherter for signing me up for this gig. I look forward to meeting those in the Lansing area.