Explore the CLR World in WINDBG [6] AppDomain's creation process

xiaoxiao2021-03-06  106

Original: http://www.blogcn.com/User8/flier_lu/index.html? Id = 3024651

We know that the CLR is running in the logical space called AppDomain, and AppDomain is between the operating system level process and the thread concept, and has the closure of the lightweight and process of threads. Appdomain.createDomain creates a new appdomain. In this way, there is a problem with a chicken or an egg seed chicken. This Appdomain.createDomain method is definitely called in an appdomain that is loaded into the appdomain type, but this appdomain is called Appdomain.createDomain method. What is created? Ha ha, we can use the EEHEAP commands of Windbg SOS to get the currently running AppDomain by listing the heap information of the CLR execution engine. We take the code below as an example.

The following is the program code: /// Appdomain.cs // useing system; public class entrypoint {public static void main (string [] args) {console.out.writeline ("Hello Appdomain!" [IMG] / images / Wink.gif [/ img]; console.in.readline ();}}

The output of this typical CLR program is as follows:

The following is quoted:

0: 003>! EEHEAP

succeeded

Loaded Son of Strike Data Table Version 5 from "E: WindowsMicrosoft.Netframeworkv1.1.4322mscorwks.dll"

Loader HEAP:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

System Domain: 793E6FC8

Lowfrequencyheap: 00960000 (2000: 00001000)

Size: 0x00001000 (4096) BYTES.

HIGHFREQUENCYHEAP: 00962000 (8000: 00001000)

Size: 0x00001000 (4096) BYTES.

Stubheap: 0096A000 (2000: 00001000)

Size: 0x00001000 (4096) BYTES.

Total Size: 0x3000 (12288) BYTES

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Shared Domain: 793E83F8

Lowfrequencyheap: 00990000 (2000) 06C40000 (10000: 00007000)

Size: 0x00009000 (36864) bytes.

HIGHFREQUENCYHEAP: 00992000 (8000: 00001000)

Size: 0x00001000 (4096) BYTES.

Stubheap: 0099A000 (2000: 00001000)

Size: 0x00001000 (4096) BYTES.

Total Size: 0xB000 (45056) BYTES

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Domain 0: 147330

Lowfrequencyheap: 00970000 (2000) 06C60000 (10000: 00004000)

Size: 0x00006000 (24576) BYTES.

HIGHFREQUENCYHEAP: 00972000 (8000: 00004000)

Size: 0x00004000 (16384) BYTES.

Stubheap: 0097A000 (2000: 00001000)

Size: 0x00001000 (4096) BYTES.

Total Size: 0xB000 (45056) BYTES

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

JIT Code HEAP:

Normal Jit: 06C80000 (10000: 00002000)

Size: 0x00002000 (8192) bytes.

Total size 0x00002000 (8192) bytes.

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Total loaderheap size: 0x1b000 (110592) BYTES

========================================

Generation 0 Starts AT 0x04AA1040

Generation 1 Starts AT 0x04AA1034

Generation 2 Starts AT 0x04AA1028

Segment Begin Allocated Size

04AA0000 04AA1028 04AA4000 00002FD8 (12248)

Large Object Heap Starts AT 0x05AA1028

Segment Begin Allocated Size

05AA0000 05AA1028 05AA6000 0x00004FD8 (20440)

Total Size 0x7fb0 (32688)

------------------------------

GC Heap Size 0x7fb0 (32688)

We can see that although this program is very simple, there is no copy of apphain, but in fact, the CLR has three appdomain: "system domain", "shared domain" and "domain 0". Further use the dumpdomain command to view three appdomain:

The following is quoted:

0: 003>! Dumpdomain 793e6fc8

Domain: 793E6FC8

Lowfrequencyheap: 793e702c

HIGHFREQUENCYHEAP: 793E7080

Stubheap: 793E70D4

Name:

AskEMBLY: 00158E48 [mscorlib]

ClassLoader: 00158F20

Module Name

79b66000 E: WindowsMicrosoft.Net Rameworkv1.1.4322mscorlib.dll

0:003>! Dumpdomain 793e83f8

Domain: 793e83f8

Lowfrequencyheap: 793e845c

HIGHFREQUENCYHEAP: 793E84B0

Stubheap: 793e8504

Name:

0: 003>! Dumpdomain 147330

Domain: 00147330

Lowfrequencyheap: 00147394

HIGHFREQUENCYHEAP: 001473E8

StUBHEAP: 0014743C

Name: appdomain.exe

AskEMBLY: 0015C2C0 [Appdomain] ClassLoader: 00161008

Module Name

00161D50 D: EmpAppdomain.exe

We can see that System Domain is actually designed to load Mscorlib.dll's BCL base library; Shared Domain is temporarily not used; and Domain 0 is responsible for running our target Assembly. We can guess System Domain is the CLR specifically to load the system base library, and the system will further use this Mscorlib to create other Appdomain to run user target Assembly. We will then look at the related code of Rotor, whether it can be confirmed. In the CLR startup, it is responsible for the EESTARTUP function (VMCEEMAIN.CPP: 206) when the execution engine is loaded, and it can be found that this function will first call the systemdomain :: attach function to load systemdomain after performing basic initialization, then load and initialize exception processing, JITER, etc. Support code, and finally call the SystemDomain :: init function to complete the initialization systemdomain and so on. SystemDomain :: attach function (vMAppdomain.cpp: 912) Mainly completes four parts: initialization system stub manager and systemDomain's static member variables; constructs and initializes the SystemDomain object in the memory area of ​​global static array g_psystemdomaInmemory, and save the pointer to M_psystemDomain static variables, used in the future to determine if SystemDomain is constructed; construct the default appdomain; construct Shareddomain. The brief function code of the function is as follows:

The following program code is: SystemDomain * SystemDomain :: m_pSystemDomain = NULL; static BYTE g_pSystemDomainMemory [sizeof (SystemDomain)]; HRESULT SystemDomain :: Attach () {// determines whether SystemDomain been configured _ASSERTE (m_pSystemDomain == NULL); if ( ! m_pSystemDomain = NULL) return COR_E_EXECUTIONENGINE; // initialize the system stub manager and static member variables of SystemDomain // ... // constructor SystemDomain objects m_pSystemDomain = new (& g_pSystemDomainMemory) SystemDomain (); if (m_pSystemDomain == NULL) return COR_E_OUTOFMEMORY ; // initializes SystemDomain objects HRESULT hr = m_pSystemDomain-> BaseDomain :: Init (); // Setup the memory heaps if (FAILED (hr)) return hr; m_pSystemDomain-> GetInterfaceVTableMapMgr () SetShared ();. // default constructor Provincial appdomain hr = m_psystemdomain-> createdefaultDomain (); if (Failed (HR)) Return HR; // Constructs Shareddomain HR = SharedDomain :: attach (); returnh HR;} It is worth noting that in order to make SystemDomain's constructive Will fail, systemdomain, and its base class baseDomain are empty, and the initialization code is placed in the init method, and many types of code in the CLR use a similar mode to ensure the success of the construction to ensure the success of the construction. The BaseDomain :: init function is directly called in SystemDomain :: attach to initialize the parent class of SystemDomain; systemdomain :: init function is called at the end of the EESTARTUP function mentioned above, and discusses it later.

The BaseDomain :: init function (vmappdomain.cpp: 310) In addition to initializing a large pile of member variables to initialize the BaseDomain object, the main burden of initialization of the heap and cache. The stack in the CLR is actually existing in each appdomain, which is why we just use the eEHEAP command to enumerate the reason for Appdomain. After initializing BaseDomain, set the SystemDomain's interface vtable mapping table to sharing because SystemDomain is responsible for the type of Mscorlib that is loaded. This is actually used in AppDomain.

Then Systemdomain :: Attach will call the SystemDomain :: CreateDefaultDomain function (vmappdomain.cpp: 2522) Constructing the default Appdomain, which is "Domain 0" in the previous test, which is used as the user-loaded user specified asMBLY execution. This function simply calls SystemDomain :: newdomain functions to construct new Appdomain instances in non-Managed mode; then set this appdomain to default Appdomain. The following is the program code: hResult systemdomain :: cretedefaultdomain () {hResult HR = S_OK; / / Prevents multiple initialization IF (m_pdefaultdom "= null) Return S_OK; // Construct a new Appdomain instance appdomain * pdomain = in non-Managed mode NULL; if (HR = newdomain)) Return HR; // Set this appdomain to the default appdomain pdomain-> getsecurityDescriptor () -> setDefaultAppdomainProperty (); m_pdefaultdomain = pdomain; // ...}

SYSTEMDOMAIN :: Newdomain function (vmappdomain.cpp: 2480) After constructing AppDomain instance, notify this appdomain it loaded asSembly; finally calls Appdomain :: setupsharedStatics function (vMAppDomain.cpp: 4583) constructs and initializes an internal class System.sharedStatics. This class is used to generate a globally unique GUID, which is used in system.runtime.remoting.Identity.ProcessIDGUID and security related types.

At the end of the SystemDomain :: Attach function, the Shareddomain :: attach function is called and initialize SharedDomain. This SharedDomain is responsible for the sharing assembly of AppDomain-neutral. I have written an article before

"CLR program under. NET platform discusses the strategy loaded into assembly sharing, interested friends can take a closer look, here is extracted:

The following is quoted:

The following three parameters are used to specify the accessory to load optimization strategy. We will discuss in detail.

STARTUP_LOADER_OPTIMIMIMIMIZATION_SINGLE_DOMAIN = 0x1 << 1,

STARTUP_LOADER_OPTIMIMIZATION_MULTI_DOMAIN = 0x2 << 1,

STARTUP_LOADER_OPTIMIMIZATION_MULTI_DOMAIN_HOST = 0x3 << 1,

...

CLR When performing an accessory, CLR will create a new application, put this accessory in a new application. If multiple applications are used to use a accessory, it is necessary to involve the previously mentioned load optimization strategy. Most The simple method is to use the startup_loader_optimization_single_domain flag, each application has a separate accessory image, the fastest, most convenient to manage, but more memory. Compared to all application domain shares a mirror image, Saving in memory using the startup_loader_optimization_multi_domain flag, but there is data such as static variables in this accessory, because to ensure that each application has independent data, it will certainly affect the efficiency. The discussion is to use (using startup_loader_optimization_multi_domain_host flag At this time, only those accessories with Strong Name will be shared by multiple application domains.

转载请注明原文地址:https://www.9cbs.com/read-124468.html

New Post(0)