More Efficiently Debug the Managed Heap Using SOS 4.5

More often than not, when we investigate the managed heap using SOS we use the all powerful !DumpHeap command. It's an incredibly useful command to get in depth detail on what currently resides on the heap. Let's look at an example of the abbreviated output from !DumpHeap -stat:

 

      MT Count TotalSize Class Name

...

...

737bc460 26 728 System.RuntimeType
737bca30 12 768 System.Int32[]
737bca68 51661 619932 System.Int32
7376b180 31 935720 System.Object[]
0055cf08 48361 1771906 Free
737bb2a8 151831 6022544 System.String

The highlighted line above tells us that we have roughly 150,000 instances of strings on the managed heap that occupies about 6MB of memory. Not a huge amount of memory but concerning nonetheless since in this particular application I don't expect it to ever have this many instances of a string type laying around. Hence, my conclusion is that we are somehow "leaking" (or rather, holding on to for far too long) 150,000 instances of strings when we shouldn't be. Now it's a simple matter of figuring out who references those instances and why. Or is it really that simple? If we step back and think about what !DumpHeap -stat is telling us - there are 150,000 instances of strings but it doesn't tell us anything whether those instances are still alive or not. For example, a good chunk of the above instances might not be referenced and are therefore eligible for garbage collection. In those cases, we're not really interested in investigating further since they are about to get cleaned up. How do we know which instances (out of the 150,000) are alive or dead? Well, we can certainly run !gcroot on all of them but chances that by the time you got to instance 10 you'd be falling asleep at the wheel. Luckily - in SOS 4.5 there are two additional switches to the !DumpHeap command:

  • -live : Indicates that you only want !DumpHeap to output instances that are considered alive.
  • -dead : Indicates that you only want !DumpHeap to output instances that are considered dead (and therefore eligible for garbage collection).

With those two switches, our exercise now goes from spending a ridiculous amount of time manually running !gcroot to simply adding the -live (or -dead) switch. In the example above, once I ran !DumpHeap -stat -mt 737bb2a8 -live I got the following output:

0:005> !DumpHeap -stat -mt 737bb2a8 -live
Statistics:
      MT Count TotalSize Class Name
737bb2a8 100167 4782606 System.String
Total 100167 objects

This means that out of the total of 150,000 instances 100,000 are considered alive and the rest will eventually be garbage collected.

The addition of -live/-dead switches to !DumpHeap can save a great deal of time when chasing down which objects on the managed heap are considered dead/alive and can dramatically reduce the amount of time spent on debugging excessive memory usage in .NET applications.

Happy Debugging!