Pavel's Blog

April 3, 2012

The most used command in the SOS extension DLL is probably !dumpheap. This command is able to show every object on the managed heap. This capability has no match within Visual Studio. The reason is that Visual Studio uses the CLR debugging API, that doesn’t seem to have this capability.

At first glance, the ICorDebugProcess interface has the perfect method: EnumerateObjects. What could be better than that? Unfortunately, the documentation states that this method is not implemented… bummer.

A while back I created a project CLR Explorer. This was supposed to be a tool to look at managed processes. Looking at metadata was easy enough, but runtime information was scarce, as the debug interfaces did not have a way to get managed heap information.

With .NET 4.5. beta released, I looked through the debug interfaces. I wanted to see if anything changed since CLR 4. I discovered there is a new interface supposedly supported on a CorDebugProcess object, ICorDebugProcess5. This new interface (the previous one was ICorDebugProcess3 – clearly the number 4 was to be avoided to not give the false impression that this is available with CLR 4).

This new interface has a method named EnumerateHeap – great! finally… and the method seems to be documented as having an actual implementation.

Now we need to initialize the ICorDebug object and attach to the process to debug:

hr = spDebug->Initialize();

CComObject<CDebugManagedCallback>* pHandler;

pHandler->CreateInstance(&pHandler);

spDebug->SetManagedHandler(pHandler);

CComPtr<ICorDebugProcess> spProcess;

hr = spDebug->DebugActiveProcess(pid, FALSE, &spProcess);

The CDebugManagedCallback class is a local C++ COM class that is the handler for debugging events. I will not show this one here (you can check out the CLR Explorer project to see one such class in action). For the purpose of this post, it really is just there so ICorDebug would be happy.

Now for the fun part. Can we get an ICorDebugProcess5? If we can, let’s use it:

The ICorDebugProcess5::GetGCHeapInformation gets some basic info for the heap. Then we can enumerate the objects on the managed heap. The GetCount method on the enumeration interface is not implemented, which makes perfect sense, since this information is unknown to the CLR, would be expensive to keep track of, and adds no real value.