Why all .NET developers need a memory profiler

It is one of the dirty secrets of software development: the number of memory leaks that find their way into production code. Memory leaks are a special category of bug because they can easily go unnoticed. The user's perspective is that they start work using your application and everything is fine. If it is an application that is used lightly, maybe run once every morning to create a report, than everything is fine for ever. If it is a long-running application then eventually it will cause problems, though the user may not know which bit of software is to blame. Since Windows rarely runs out of memory, the user might just notice everything slowing down. It is one of the reasons why restarting Windows from time to time tends to be beneficial.

The huge amounts of RAM in today's machines disguise memory leaks. An application can leak a little bit of memory with every operation, and still run fine for ages. That's not good though; and the migration to web applications makes the problem worse. Web applications tend to be exercised heavily for long periods, which means memory leaks are more likely to have severe consequences.

Although garbage collection in the .NET Framework is meant to relieve developers of the burden of memory management, the reality is a little different. In some respects managed code is more prone to memory leaks than unmanaged code. The problem is that the garbage collector will only free objects for which no valid references exist, and it is easy to maintain such references inadvertently.

So how do you find these guys? You observe memory usage externally with a utility like Sysinternals Process Explorer, or write your own tests with code such as calls to GC.GetTotalMemory, or use a dedicated tool. There are performance tools built into some versions of Visual Studio, which can be configured to do .NET memory profiling, though making sense of the reports takes some effort. If you want to try this in Visual Studio 2008, open the Performance Explorer, right-click a Performance session, and check the boxes for .NET memory profiling collection. This can be useful, though I'm going to suggest a third-party tool which is modestly priced and more productive: Scitech .NET Memory Profiler. Others worth investigating include Micro Focus DevPartner Studio (which does far more than just memory profiling) and Rational Purify Plus.

Here is a quick example. Let's say I'm writing a VB.NET Windows Forms application. I have a main Form1, and a second Form2 which I create and display as needed. I want to have the second form respond to events on the main form, so in Form2 I declare a reference to Form1, which I set when Form2 is displayed:

Private WithEvents mainForm As Form1

Using the Visual Studio editor I hook up an event handler for mainForm.

Everything works fine, until a user complains that the more she uses the app, the more her machine slows down. What's the problem? Well, if you run the Performance Explorer with memory profiling enabled, you might notice something odd. Run the app, and display and close Form2 three times over. The report tells us (among many less useful things) that there were three instances of Form2 created, and that all three were alive at the end. We've found a memory leak.

 

What's the problem? You can guess that it is something to do with the reference to Form1. The Scitech memory profiler easily identifies the exact problem. In order to find it, run the application in a Memory Profiler session, then immediately choose Collect Heap Snapshot. Open and close the three instances of Form2, then again Collect Heap Snapshot. Finally, filter the view to show new or removed instances only. You can see that the number of instances of Form2 is now 3, where it should be 0. Double-click this line in the report to see a list of instances, and double-click the first to see the references to it that are preventing it from being garbage-collected. Although there are several of these, only one really matters, which you can find by checking the option Only show instances included in root paths. The culprit is an instance of System.EventHandler.

 

You can actually fix this memory leak without changing the way the app works. Remove the handles clause from the event handler for the mainForm reference, and replace it with a manual event hook-up in the Form2 constructor:

AddHandler mainform.Click, AddressOf mainform_Click

Then, override Dispose and manually remove the event handler:

RemoveHandler mainform.Click, AddressOf mainform_Click

Try the application again under a profiler, and you'll see that the problem has disappeared, and no instances of Form2 remain in memory after it is closed.

No doubt there are other, better ways to code this application; but it illustrates the troubleshooting process.

The reason this kind of leak is so troublesome is the chain effect. If a form remains in memory, so too do all the objects referenced by that form, and so on. Unfortunately there are occasionally bugs in the Framework itself that make this hard to avoid - see for example this post by the author of Memory Profiler, Andreas Suurkuusk, where he tracks down a problem with the toolstrip control.

I'd argue that .NET applications of a significant size are more likely than not to have some memory leak issues, and that a tool like Memory Profiler is near-essential for troubleshooting them.

0 TrackBacks

Listed below are links to blogs that reference this entry: Why all .NET developers need a memory profiler.

TrackBack URL for this entry: http://www.itjoblog.co.uk/blogadmin/mt-tb.cgi/111

3 Comments

Stephen said:

Nice blog post Tim. You mention third party tools for memory profiling your app. Have you tried the latest ANTS Memory Profiler from Red Gate?

http://www.red-gate.com/products/ants_memory_profiler/index.htm

Its had a complete rewrite but you should judge for yourself as I�m a bit biased. :)

To track down references there's a graph allowing you to easily visualize which objects are still referencing other objects:

http://www.red-gate.com/products/ants_memory_profiler/screenshot_gallery/ObjectGraph.gif

It can also automatically identify objects that are being kept in memory by EventHandlers or those which Dispose() has been called but are still in memory making memory leak finding and fixing even easier.

Kind regards,

Stephen

Ian Smith said:

Nice article Tim.

Don't forget that for those of us programming Silverlight there's a nice (if admittedly basic) Memory/CPU analysis tool in the excellent Silverlight Spy product from First Floor Software (free for Silverlight 2, about USD99 for Silverlight 3, but currently available as a free public beta).

I agree that the value of an memory profiler/heap analyzer is often underestimated by people using languages with an Garbage collecotr.

There's also Yourkit for .Net, which allows you to analyze heap dumps.
Note that Java is ahead in this area with the free and open source Eclipse Memory Analyzer (http://www.eclipse.org/mat/)

Leave a comment

Current Vacancies from CWJobs

(* Required field)










Preferred format