« Home | Shut the ding up » | Xwin32 MacroView Fonts » | ADSL2+ » | Task Bar Positioning » | Sysinternals to the rescue » | Cryptic IBM Filenames » | Regex Fail All » | Triplet » | csharpformat test » | ADO.NET Black Helicopters »

.NET Memory Leaks

Conceptually I knew that eventually there would be a need to diagnose a memory leak problem in a .NET application. Sure a garbage collected environment automatically sorts out whole sets of memory problems, but it doesn’t stop memory leaks where you put an object in some container and “forget” about it. You legitimately need the container to hang around, but the object should have been chucked in the garbage. Its actually quite easy to do, so its surprising that four years of C# development work has passed without the need to resolve a memory leak issue until today.

There have more than likely been other memory leaks but they haven’t become an issue. The vast memory available in modern machines and the typical life cycle of some classes of programs help to hide the occurrence of memory leaks. For example an end user closing their application at “quittin time” means that most Windows form app scenarios get a clean start every day. This a cheat’s way of resolving memory leaks!

Experience with C++ has shown, you don’t stuff around with trying to sort out memory leaks using manual coding techniques. The best approach is to leverage a tool otherwise you waste a ton of time. The first tool I tried was the beta release of dotTracer 2.0 from http://jetbrains.com. Being somewhat of a collector in nature, dotTracer was tried first because of a recent purchase of Resharper which has been going well. Unfortunately the beta functionality wasn’t quite there yet to practically resolve the memory leak issue.

Since I already have Purify for all C++ memory analyis, it was worth giving it a go on a .NET problem. Running a .NET program through Purify memory analysis resulted in sluggish performance for the application during profiling. It was bearable but .NET specific memory profilers seem to run the profiled apps much faster. Quick app runs make it easier to go through a debug cycle and chase down problems. Also the user interface for analyzing object instance differences was hard to work with.

The next memory profiler that was used was from http://memprofiler.com. I had actually experimented with it out of interest a while back. My memory of it was of an intimidating user interface i.e. hundreds of thousands of object references staring at you from behind a grid. Now that there was a real problem to sort out, some effort was put into understanding the user interface. It turned out to be very effective in identifying which objects shouldn’t be around and traversing the object relationships to figure out what is keeping them around. The first impression is that fancy graphics showing object relationships via graphical links/trees should be an easier to use metaphor for identifying memory leaks. In practice it turns out that being able to quickly traverse the relationships between the objects in memory is more useful in identifying the cause of objects hanging around when they shouldn’t.

Memory leak identification in .NET is based around running a program to a certain point and then taking a snapshot. This acts as a base line for the objects you expect to be in memory. You then perform a program task and complete the task so that you would expect the managed object status to be the same as that in the base line snapshot. An example is closing a form once you’ve done with the form. The memory profiler’s comparison tool can then be used to look at the difference in object instances between the base line and another snapshot. The live objects in this difference set are the potential memory leaks.

Cutting a long story short, my memory problem was identified by using the http://memprofiler.com tool. It was due to an interaction between a long lived business object list and a shorter lived form. The form subscribed to a ListChanged event in the business object but didn’t unsubscribe when the form was closed. So even though the form was closed, the long lived business object kept the form object from being garbage collected. Form references were being accumulated in the ListChanged delegate’s linked list causing the memory leak. Being a cheapskate I’ll hold off buying the profiler tool until its next needed, but at least then its a straight forward buy based on experience.

 

Links to this post

Create a Link