unmanaged vs managed.

G

Guest

Thanks guys. I think that all my questions are
answer 110% above my expectations. :) :) :)

Thanks Chris for answering most of the Qs,
and thanks Willy for answering my last Q.

BTW Willy, Great job on the articals at codeproject. :)
 
W

Willy Denoyette [MVP]

Chris Mullins said:
I didn't know that. Do you know any blogs or suitable docs I can go read
more at?

Not that I'm aware of.
I've read the MSDN article on this at:
http://msdn.microsoft.com/msdnmag/issues/05/05/JITCompiler/

... but I would love to read more.

Above (otherwise excellent) article is based on what is found in SSCLI (V1)
and does not reveal that much about the CLR memory manager's internals, nor
does it include anything really useful about the GC and the JIT
implementation in the commercial CLR product.
So, if you don't have access to the CLR's source code, all you can do is
peek around in a managed application process, using WinDbg (or CDB).
Note that in following I denote by *Heap*, the "Heap Managers" heap(s),
while with *GC-Heap* I denote the CLR managed heap(s).
It's quite obvious that the CLR has it's own memory manager, after all the
*GC-Heap* is THE CLR's private heap, no other component in the system
uses/manages the GC-Heap but the CLR. Note also that the GC cannot possibly
allocate from the *heap*, allocated heap memory cannot move!
To inspect the heaps available in in a process, you can use the !heap
(native) debugger command, use this command to get all possible info about
the "Heap Manager's" heaps. To inspect the GC-Heap you'll have to use the
SOS debugger extension commands.

For instance if you load a simple managed program in the Windbg debugger,
you can peek at the initial heaps created by the OS and the Mscoree.
When you start Windbg <some program>, the debugger will break at an initial
break point after the image and the statically linked modules are loaded
(ntdll, kernel32 and Mscoree).
At this point, !heap will show you the "default" heap plus a number of heaps
owned by Mscoree, at this point the CLR isn't yet loaded/initialized, so
there is no GC-Heap yet available.
At this point you can set a breakpoint at "Mscoree!_CorExeMain" and run,
the debugger breaks at a point before the CLR calls your main entry point.
When you watch the heaps created so far, you'll notice a couple of
additional heaps, these are created by the CRT and the CLR debugger thread.
You can inspect the heap locations in memory by entering the
"!address -RegionUsageHeap" command.
Note that the "RegionUsageHeap" only shows the heap allocated memory
regions. To watch the GC-Heap you'll have to load sos.dll and enter the
!eeheap -gc command.
Notice the address of the ephemeral segments, these do not map to the heap
segment addresses (regions), because they are taken from the VAS (using the
VMM API's).
You can inspect the regions allocated by the GC-Heap by entering
!Address -RegionUsageIsVAD.
You see, the CLR memory manager uses the VMM to allocate memory for the
GC-Heap(s) (and a bunch of other heaps private to the CLR, like the JIT
heap, the loader heap, etc...).
At this point, we have a couple of heaps and a bunch of CLR owned heaps in
the process.
Question is who uses the different heaps, well it depends, a managed
application can allocate from the default process heap by calling one of the
Marshal class API's.
For instance, Marshal.AllocHGlobal allocates directly from the "default"
process heap (also called the Base Heap), using the "Heap Manager" APi's.
Marshal.AllocCoTaskMem also allocates, be it indirectly via the COM memory
allocator (using ole32!CoTaskMemAlloc), from "default" process heap. The CLR
Object Manager allocates from the GC-Heap, while the GC keeps the GC-Heap
"clean" in close cooperation with the CLR Memory Allocator or an external
Memory allocator like the one used when you run the CLR in the SQL Host.
The other heaps, are used by the CRT allocator, unmanaged code uses this
heap whenever some module calls malloc/free or new/delete functions.
You can drill down quite a bit deeper into this, by seting appropriate
breakpoints at run-time, for instance to watch the GC-Heap allocator at
work, you can set a breakpoint at kernel32!VirtualAllocEx and start
allocating some objects.
You can also set breakpoints at ole32!CoTaskMemAlloc or
ntdll!RtlAllocateHeap in order to inspect other heap allocator actions
triggered by Marshal.AllocCoTaskMem and/or Marshal.AllocHGlobal
respectively, watch the memory locations they are allocating from using
!heap -a.

There's a lot more to tell about this, but I hope this will help you a bit
to get a better idea about the heap usage in a managed process.
Willy.
 
C

Chris Mullins [MVP - C#]

I'm suffering from information overload!

I'll poke at things a bit with WinDbg & SOS later today, and give all your
suggestions a shot. I'll end up all the wiser for it...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top