Here’s how I track down memory leaks in my .Net apps – level 400

I was planning on posting this anyway, but Steve’s post has convinced me to do it sooner.  Here are methods and tools I use to track down memory leaks in my applications. 

  • First, I profile my app.  I do web applications, so I’ll use Application Center Test that comes with VS 2003 EA, but you can also use the free tool, Microsoft Application Stress Tool.

  • I run perfmon while the stress tool is running.  The stress tool will push my app to the limit and simulate heavy traffic.  Here are counters I ALWAYS look at:

    • # of Excepts Thrown /sec (0 is the number you are shooting for.

    • Gen 0 heap size

    • Gen 1 heap size

    • Gen 2 heap size (this is where your memory will likely accumulate.  If you have objects that won’t go away, they will end up here and end up taking up ALL your memory)

    • Large Object Heap size

    • Application Restarts (if your memory usage gets too high, ASP.NET might automatically restart the AppDomain, and you’ll be able to see it here).

    • Any others you feel are appropriate.

  • Run the stress tool while watching the performance counters.  Your memory usage should go up and down but overall remain consistent.  If your gen 2 keeps getting bigger and bigger and bigger, then you probably have a memory leak.

  • Here is how I go about finding out exactly what objects are taking up all my gen 2 memory

    • Bookmark the C# Team’s Tools page.  There are several memory profilers to choose from.  There are several commercial products you can buy, but I chose to try the free one: Allocation Profiler.  I also tried NProf, but it seemed to profile processor performance and not memory (unless I used it wrong).

    • Note, for AllocationProfiler or NProf to work, you have to modify your machine.config file’s <processModel/> node to have username=“SYSTEM“ instead of “machine“.

    • Open AllocationProfiler, and have it start profiling your app.

    • I would run the stress tool on my web apps to generate a lot of traffic.  When I’m done, I stop profiling.  Application Profiler generates some good graphs from its logfile.  I look at where the memory is allocated, and I see generation 2 has a bunch of stuff.  I can see what types make up the most memory.  You can also look at the contents of the managed heap with other views, and you can drill down and determine what is taking up all your memory.  Once you have found the offending type, you can dig into your code and look for no-nos.

  • Read my previous post about my nasty memory leak.

  • If would also do you good to read Jeffrey Richter’s book: Applied Microsoft .Net Programming in C#.  It has a great section about the managed heap and garbage collector.

  • Once you know how the managed heap and garbage collector work in .Net (and no sooner), you can evaluate your code for scenarios where long-lived objects keep references to other objects and thereby prohibit the garbage collector from reclaiming their memory.

  • Example:  If you have a long-lived object that has long strings as members, the memory those strings consume cannot be collected as long as the long-lived object is alive. 

I hope this helps someone find memory leaks in their application.  Practice makes perfect, and I had to read books and articles to understand the inner workings of the CLR before I could effectively analyze my code for leaks.