I'm reading the article
JIT and Run: Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects by Hanu Kommalapati and Tom Christian. It's an excellent article. It's real internal and worth reading three times throughly. This post is my first notes on this article.
Before the CLR executes the first line of the managed code, it creates three application domains: the System Domain, the Shared Domain, and the Default AppDomain. The first two are singleton and can only be created through the CLR bootstrapping process facilitated by the shim—mscoree.dll and mscorwks.dll (or mscorsvr.dll for multiprocessor systems). The third is an instance of the AppDomain class that is the only named domain. Additional domains can be created from within managed code using the AppDomain.CreateDomain method or from unmanaged hosting code using the ICORRuntimeHost interface.
System DomainThe SystemDomain is responsible for creating and initializing the SharedDomain and the default AppDomain. It loads the system library mscorlib.dll into SharedDomain. It also keeps process-wide string literals interned implicitly or explicitly.
SystemDomain is also responsible for generating process-wide interface IDs, which are used in creating InterfaceVtableMaps in each AppDomain. SystemDomain keeps track of all the domains in the process and implements functionality for loading and unloading the AppDomains.
SharedDomainAll of the domain-neutral code is loaded into SharedDomain. Mscorlib is automatically loaded into SharedDomain. Fundamental types from the System namespace like Object, ValueType, Array, Enum, String, and Delegate get preloaded into this domain during the CLR bootstrapping process. User code can also be loaded into this domain, using LoaderOptimization attributes specified by the CLR hosting app while calling CorBindToRuntimeEx. SharedDomain also manages an assembly map indexed by the base address, which acts as a lookup table for managing shared dependencies of assemblies being loaded into DefaultDomain and of other AppDomains created in managed code.
DefaultDomainDefaultDomain is an instance of AppDomain within which application code is typically executed. Each AppDomain has its own SecurityDescriptor, SecurityContext, and DefaultContext, as well as its own loader heaps (High-Frequency Heap, Low-Frequency Heap, and Stub Heap), Handle Tables (Handle Table, Large Object Heap Handle Table), Interface Vtable Map Manager, and Assembly Cache.
The default AppDomain can't be unloaded and hence the code lives until the CLR is shut down.
LoaderHeapsEach application domain has its own loader heaps. LoaderHeaps are meant for loading various runtime CLR artifacts and optimization artifacts that live for the lifetime of the domain. These heaps grow by predictable chunks to minimize fragmentation. The GC Heap hosts object instances while LoaderHeaps hold together the type system. Frequently accessed artifacts like MethodTables, MethodDescs, FieldDescs, and Interface Maps get allocated on a HighFrequencyHeap, while less frequently accessed data structures, such as EEClass and ClassLoader and its lookup tables, get allocated on a LowFrequencyHeap. The StubHeap hosts stubs that facilitate code access security (CAS), COM wrapper calls, and P/Invoke.
Mscorlib.dll is loaded into the SharedDomain but it is also listed against the SystemDomain. The SystemDomain and the SharedDomain use the same ClassLoader, while the Default AppDomain uses its own.
The HighFrequencyHeap initial reserve size is 32KB and its commit size is 4KB. LowFrequencyHeap and StubHeaps are initially reserved with 8KB and committed at 4KB. Each domain has a InterfaceVtableMap that is created on its own LoaderHeap during the domain initialization phase. The IVMap heap is reserved at 4KB and is committed at 4KB initially.
Global HeapsThere are four global heaps outside all the application domains: Process Heap, JIT Code Heap, GC Heap, and LOH Heap. The just-in-time (JIT) compiler generates x86 instructions and stores them on the JIT Code Heap.