One of these days Microsoft will release a version of .NET where we don’t have to worry about memory. HA! Who am I kidding!? All you worry about in a .NET application is the memory. Naturally, I personally never want Microsoft to come out with the memory worry free .NET because I’d be out of a job.

With SOS for .NET 4.5, there’s not a whole lot different but there are two differences that will be valuable. The first are two new options to the most important SOS command, !dumpheap. One of the big problems in dealing with those minidumps from production systems is trying to figure out which objects are rooted, meaning have references and cannot be garbage collected, and those objects that are ready for garbage collection. That problem is easy to solve with the new –live and –dead options. Get in the habit now of always passing –live when you first do that initial !dumpheap –stat because that’s all you care about!

Here’s an example output comparing the differences reported by –stat alone, -live, and –dead.

  1. >0:000 !dumpheap stat
  2. . . .
  3. 000007feefedadd8    21567      2616488 System.Object[]
  4. 000007feeff34198   336164      8067936 System.Int32
  5. Total 509034 objects
  7. >0:000 !dumpheap stat live
  8. . . .
  9. 000007feefedadd8      135       285048 System.Object[]
  10. 000007feeff2d8f0    19703       472872 System.WeakReference
  11. Total 22711 objects
  13. >0:000 !dumpheap stat dead
  14. . . .
  15. 000007feefedadd8    21432      2331440 System.Object[]
  16. 000007feeff34198   336158      8067792 System.Int32
  17. Total 486286 objects

What I haven’t been able to figure out is that the total objects between live and dead objects never add up to the total shown when looking at all objects with just the –stat switch. Doing some experimentation the output for –live looks valid so I’m going to trust it for now. I’ll talk to the CLR team and see if this is a bug or there’s a real reason for the discrepancy. It’s not like an object could be alive and dead at the same time… unless it was a ZOMBIE! No matter, the –live switch looks fantastic and will save everyone a huge amount of time.

Since everyone is not moving over to .NET 4.5 immediately, I tried like crazy to see if I could get the .NET 4.5 SOS version working with minidumps from .NET 4.0. Nothing I tried and no amount of playing around with .cordll to load the MSCORDACWKS.DLL from .NET 4.0 would work. Do yourself a favor now and make sure you save off SOS.DLL, CLR.DLL, and MSCORDACWKS.DLL from a pure .NET 4.0 installation because .NET 4.5 is on top of .NET 4.0. I’ll keep working on trying more tricks to get !dumpheap –live working with .NET 4.0.

The second SOS command to get some development love is !clrstack. There’s a new experimental option –i, which uses the CLR Debugging API’s ICorDebug interface to walk stacks and show variable names very much like the !mk command in SOSEX. It’s very important that to use !clrstack –i you have the _NT_SYMBOL_PATH environment variable set to include the public Microsoft symbol server. SOS needs access to MSCORDBI.DLL through the symbol server download even though that DLL is in the framework directory along with SOS.DLL.

Running !clrstack –a –i will show output like the following snippet. What you can’t see is that the output is that it’s fully DML ready.

  1. 00000000002fdca0 000007feefda060f [DEFAULT] [hasThis] Object System.Delegate.DynamicInvokeImpl(SZArray Object) (C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll)
  4.   + (Error 0x80131304 retrieving parameter 'this')
  5.   + (Error 0x80131304 retrieving parameter 'args')
  7. LOCALS:
  8.   + (Error 0x80004005 retrieving local variable 'local_0')
  9.   + (Error 0x80004005 retrieving local variable 'local_1')

You are probably wondering where the actual values are. Just like !mk, when it’s JIT optimized code we can’t get the values. That doesn’t make !clrstack –i any less valuable because at least it shows you the types so you can use !dso, or !mdso from SOSEX, to look them up. To turn off the JIT optimizations, you’d have to either run the whole application with the COMPLUS_ZAPDISABLE environment variable or turn it off for an individual assembly with the INI file trick.

The new –live and –dead options for !dumpheap and the –i for !clrstack are the most important additions, but there are a few more worth mentioning. The !bpmd command now supports setting breakpoints on a source and line if you have the PDB file for the assembly loaded. If you’re doing heavy interop, the new !dumprcw, which dumps a Runtime Callable Wrapper, and !dumpccw, which dumps a COM Callable Wrapper, look helpful. The new SOS for .NET 4.5 is nice, but wait until you see the new version of SOSEX!