Appdomain creation process

Source: Internet
Author: User
Tags mscorlib

We know that assembly in CLR is loaded and run in the logical space named appdomain, while appdomain is between the process and thread concepts at the operating system level, at the same time, it has a lightweight thread and a closed process. You can use appdomain. createdomain: Create a New appdomain. In this way, the problem of a chicken or an egg occurs. This appdomain. the createdomain method must be called in an appdomain loaded with the appdomain type, but who calls this appdomain. what about the createdomain method? Haha
We can use the eeheap command of windbg SOS to list the stack information of the CLR execution engine and obtain the current running appdomain information. The following sectionCodeExample
The following content:ProgramCode:

//
// Appdomain. CS
//
Using 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:

Reference:

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 (0000:4000)
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 (running :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 20172fd8 (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 and does not create any appdomain by itself, the CLR actually has three AppDomains: "system domain ", "shared domain" and "Domain 0 ". The following code uses the dumpdomain command to view three AppDomains:

references:

0: 003>! Dumpdomain 793e6fc8
domain: 793e6fc8
lowfrequencyheap: 793e702c
highfrequencyheap: 793e7080
stubheap: 793e70d4
Name:
Assembly: 00158e48 [mscorlib]
classloader: 00158f20
Module name
79b66000 E: windowsmicrosoft.net rameworkv1.1.4322mscorlib. dll

0: 003>! Dumpdomain 793e83f8
domain: 793e83f8
Protocol: 793e845c
highfrequencyheap: 793e84b0
stubheap: 793e8504
name:

0: 003>! Dumpdomain 147330
domain: 00147330
lowfrequencyheap: 00147394
highfrequencyheap: 001473e8
stubheap: 0014743c
name: appdomain.exe
assembly: 0015c2c0 [appdomain]
classloader: 00161008
Module name
00161d50 D: empappdomain.exe

As we can see, the system domain is actually used to load the basic library of the Bcl mscorlib. dll; shared domain is not used for the moment; domain 0 is responsible for running our target assembly. We can guess that the system domain is specifically used by CLR to load the basic library of the system, and the system will use this mscorlib to create other AppDomains to run the user's target assembly. Let's take a look at the relevant code of the rotor and see if it can be verified.
The eestartup function (vmceemain. CPP: 206), we can find that this function first calls the systemdomain: attach function to load systemdomain, then loads and initializes the exception handling, jiter, and other support code after the basic initialization work, at last, the systemdomain: init function will be called to complete initialization of systemdomain and so on.
Systemdomain: attach function (vmappdomain. CPP: 912) initializes the static member variables of the system stub manager and systemdomain. constructs and initializes the systemdomain object in the memory zone of the Global static array g_psystemdomainmemory, save the pointer to the m_psystemdomain static variable for later usage to determine whether the systemdomain is constructed and other functions; construct the default appdomain; and construct the shareddomain. The function code is as follows:
The following is the program code:

Systemdomain * systemdomain: m_psystemdomain = NULL;
Static byte g_psystemdomainmemory [sizeof (systemdomain)];

Hresult systemdomain: attach ()
{
// Determine whether the systemdomain has been constructed
_ Asserte (m_psystemdomain = NULL );
If (m_psystemdomain! = NULL)
Return cor_e_executionengine;

// Initialize the static member variables of the system stub manager and systemdomain
//...

// Construct the systemdomain object
M_psystemdomain = new (& g_psystemdomainmemory) systemdomain ();
If (m_psystemdomain = NULL) return cor_e_outofmemory;

// Initialize the systemdomain object
Hresult hR = m_psystemdomain-> basedomain: Init (); // setup the memory heaps
If (failed (HR) return hr;

M_psystemdomain-> getinterfacevtablemapmgr (). setshared ();

// Construct the default appdomain
HR = m_psystemdomain-> createdefadomain domain ();
If (failed (HR) return hr;

// Construct a shareddomain
HR = shareddomain: attach ();

Return hr;
}

It is worth noting that in order to prevent the systemdomain construction from failing, the constructors of systemdomain and its base class basedomain are empty, and the initialization code is put in the init method, many types of code in CLR use similar patterns to separate constructor and initialization to ensure successful constructor. The basedomain: init function is called directly in systemdomain: attach to initialize the parent class of systemdomain. The systemdomain: init function is called at the end of the eestartup function mentioned above, we will discuss it in detail later.
Basedomain: init function (vmappdomain. cpp: 310) not only initializes a large number of member variables of the basedomain object, but also initializes the heap and cache. The heap in CLR actually exists in each appdomain, which is why we can use the eeheap command to list the appdomain. After basedomain is initialized, The vtable ing table of the systemdomain interface is set to share. This is because the type in mscorlib that systemdomain is responsible for loading is actually used in appdomain.
Then systemdomain: attach will call the systemdomain: createdefaultdomain function (vmappdomain. CPP: 2522) construct the default appdomain, that is, "Domain 0" in the previous experiment, and use it to load the user-specified assembly for execution. This function simply calls the systemdomain: newdomain function to construct a new appdomain instance in non-managed mode, and then sets this appdomain as the default appdomain.
The following is the program code:

Hresult systemdomain: createdefadomain domain ()
{
Hresult hR = s_ OK;

// Prevent multiple Initialization
If (m_pdefaultdomain! = NULL)
Return s_ OK;

// Construct a new appdomain instance in non-managed Mode
Appdomain * pdomain = NULL;
If (failed (hR = newdomain (& pdomain )))
Return hr;

// Set this appdomain to the default appdomain
Pdomain-> getsecuritydescriptor ()-> setdefaappappdomainproperty ();

M_pdefaultdomain = pdomain;

//...
}

Systemdomain: newdomain function (vmappdomain. CPP: 2480) is relatively simple. After an appdomain instance is constructed, the appdomain is notified of its loaded assembly, and the appdomain: setupsharedstatics function (vmappdomain. CPP: 4583) construct and initialize an internal class system. sharedstatics. This class is used to generate globally unique guids, such as system. runtime. remoting. Identity. processidguid and security-related types.

At the end of the systemdomain: attach function, the shareddomain: attach function is called to construct and initialize the shareddomain. This shareddomain is responsible for loading the shared assembly of appdomain-neutral. An article I wrote earlierArticleThe Analysis of CLR program loading principles on the. NET platform discusses the policy of loading assembly for sharing. If you are interested, please take a closer look. Here is an excerpt:

references:

The following three parameters are used to specify the accessory loading optimization policy. We will discuss them in detail later.
startup_loader_optimization_single_domain = 0x1 <1,
startup_loader_optimization_multi_domain = 0x2 <1,
startup_loader_optimization_multi_domain_host = 0x3 <1,

...

when executing an accessory, CLR creates an application domain and places the accessory to a new application domain. if multiple application domains use one accessory at the same time, the aforementioned accessory loading optimization policy is involved. the simplest way is to use the startup_loader_optimization_single_domain flag. Each application domain has an independent accessory image, which is the fastest speed and most convenient for management, but occupies a large amount of memory. the opposite is that all application domains share an image of an accessory (using the startup_loader_optimization_multi_domain flag) to save memory, but when there is data such as static variables in this accessory, to ensure that each application domain has independent data, efficiency is affected to a certain extent. the solution in the compromise is to use (using the startup_loader_optimization_multi_domain_host flag). At this time, only accessories with strong name will be shared by multiple application domains.

Shareddomain: attach function (vmappdomain. the implementation of CPP: 6440) is relatively simple. Similar to systemdomain: attach, it constructs a shareddomain object in the Global static memory allocated by g_pshareddomainmemory and calls the shareddomain: init function for initialization. The shareddomain: init function (vmappdomain. cpp: 6475) first calls the base class initialization function basedomain: init, and then initializes the Assembly ing table.

After systemdomain: attach function call and exception initialization, eestartup function calls systemdomain: init function to complete systemdomain initialization.
Systemdomain: init function (vmappdomain. CPP: 1074) First initialize the fusion system to disable the callback function, then obtain the configuration information such as the Windows System directory, and then complete the three most important tasks: load the Assembly (mscorlib) where the Bcl library is located. DLL); construct the pre-allocated exception object; construct and initialize the global String constant table.
Systemdomain: loadbasesystemclasses function (vmappdomain. CPP: 1263) First call the systemdomain: loadsystemassembly function to load mscorlib. DLL. Then, g_mscorlib.init (Binder: init) is indirectly called through the binder: startupmscorlib function to initialize mscorlib. Finally, some common types are loaded from mscorlib, such as g_pvaluetypeclass and g_parrayclass.
Systemdomain: createpreallocatedexceptions function (vmappdomain. cpp: 1019) uses the type definition just obtained to construct three pre-allocated exception objects: outofmemoryexception, stackoverflowexception, and executionengineexception. When these three exceptions are caused, the CLR stack and heap may have been damaged or overflow and cannot be constructed through the traditional memory allocation method. In. NET Framework 2.0, the concept of CER (constrained execution regions) is further proposed to ensure the certainty of local structures. If you are interested, refer to my other article finalization [2] improvements in whidbey.
The initialization of the global String constant table is relatively simple. In fact, it initializes a global hashmap with the string hash value as the key and string as the value. It is used to optimize the string performance and ensure the efficiency of cross-appdomain string transmission. If you are interested, refer to another article titled Optimization of string immutability in CLR.

So far, the process of starting system domain, shared domain, and default domain by CLR before running the user program has been basically described. The next section describes how to use these three methods together, this allows the CLR to achieve optimal space and efficiency during runtime.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.