Re: unmanaged vs managed.
- From: "Willy Denoyette [MVP]" <willy.denoyette@xxxxxxxxxx>
- Date: Thu, 1 Nov 2007 13:26:19 +0100
"Chris Mullins [MVP - C#]" <cmullins@xxxxxxxxx> wrote in message news:ewqUdf%23GIHA.4296@xxxxxxxxxxxxxxxxxxxxxxx
"Willy Denoyette [MVP]" <willy.denoyette@xxxxxxxxxx> wroteThe GC heap is a "private" memory allocator, which bypasses the *Heap Manager* to to allocate directly from the VMM.
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.
.
- Follow-Ups:
- Re: unmanaged vs managed.
- From: Chris Mullins [MVP - C#]
- Re: unmanaged vs managed.
- Prev by Date: Re: private instance constructor
- Next by Date: Re: Comparing ArrayLists
- Previous by thread: Bring To Front
- Next by thread: Re: unmanaged vs managed.
- Index(es):
Relevant Pages
|