Finding a Memory Leak in a .Net Application
Do You Have a Leak?
What do you do when you think your application has a memory leak?
About Memory Management and the GC
There have been books written on this so I’m not going to attempt to explain. However I can’t stress enough how important it is to have at least a basic understanding about how the Garbage Collector works.
To compliment their products Red Gate have created a series of easy to understand on-line video’s about .Net Memory Management nicely broken down into several 5-10 minutes segments. These video’s are FREE so watch them!
If the video’s are not in depth enough for you, any article on the subject by Jeffrey Richter should satisfy your need for detailed explanations. Start with this one.
Every time I opened and closed one of my controls, which was getting opened in a modal window, the memory used by the application increased and never went back down again. Which is weird because doesn’t .Net handle all memory management for me?
Do it does not.
So what is going on? The control in question has a dispose method, there’s nothing really tricky going on (no database connections etc) so how do I find out exactly what is causing the leak?
Finding the Leak
Enter ANTS memory profiler. I fire up the profiler, select my .exe and click ‘Start Profiling’.
The app starts like normal but now the profiler has it under a microscope. Expect your app to run more slowly and make sure you have plenty of RAM.
I navigate to the screen where I can ‘launch’ the control that is leaking, then click ‘Take Memory Snapshot’.
Then I open and close the modal window say six times then click ‘Take Memory Snapshot’ once more.
Now we have two memory snapshots which we can compare. Stop Profiling for now, two is enough.
Click ‘Class List’, then in the grid click on the ‘Instance Diff (+/-)’ column header to sort by instance differences.
What we can clearly see now is a list of objects that are ‘alive’ in the program. What we care about is the difference in live instances from the first snapshot to the second. The ‘Instance Diff’ column provides this info. Now if we have a leak we should see an extra 6 live instances for our leaky control. So scroll down to the group of +6 items.
There are a couple of things of interest here in the profiler. First is yes we can see an extra six instance of our leaky control. Secondly, notice that ANTS puts your controls in bold. In this case we are looking for a specific problem but if you wanted to check for general memory leaks you can easily use the app for a while then scroll down until you see which of your objects is regularly increasing its instance count.
Ok great, we know it leaks, now what?
Dig a Little Deeper
Highlight the leaky object and click Instance List.
That will then show all 6 instance, just select one then click the ‘Object Retention Graph’ button.
In my case the graph appears empty, until I uncheck the ‘Hide’ box.
Now there’s some useful info…
In fact this tells me that there are several KeyEventHandlers that are stopping the GC from collecting my control.
Cool so back to the code and I add some code to unregister the handlers in the Dispose method.
_previousButton.Click -= PreviousButtonClick; _familyNameText.KeyDown -= Navigate; _givenNamesText.KeyDown -= Navigate; ...
Rebuild the solution and re-run the profiler. Take the initial snapshot, open close the leaky form half a dozen times, take the second snapshot.
Now there are no more live instances of the leaky control! Our memory leak has been resolved.
It is almost certain that somewhere in your application there is a memory leak. With the right tool finding and resolving these leaks can be really easy, it just takes a little bit of time to familiarise yourself with the way the tool works.
The tools aren’t cheap but for any commercial application they are most definately worth the money. In this posting I used ANTS profiler from Red Gate, I am sure there are other tools out there that also do a great job, I just haven’t had the opportunity to use them. ANTS though is excellent (and no I do not have any association with them…beyond having bought a licence).
Events wired up to their handlers are often the ‘hidden’ cause of leaks. But even those of us who know how to manage memory in .Net often forget to do the right thing for whatever reason…usually time pressures. So I’d recommend explicitly building in some time into your project schedule to go hunting for memory leaks, find them before they go into production and everyone will sleep easier at night 🙂