注册
 找回密码
 注册
江西广告网
查看: 227|回复: 0
打印 上一主题 下一主题

谈 WinDbg 之 AppDomain 的创建过程

[复制链接]

该用户从未签到

1
跳转到指定楼层
发表于 2008-12-24 11:59:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册

x
  我们知道 CLR 中 Assembly 是在名为 AppDomain 的逻辑空间中被载入运行的,而 AppDomain 是介于操作系统层面进程和线程概念之间,同时具有线程的轻便和进程的封闭性,使用者可以通过 AppDomain.CreateDomain 创建新的 AppDomain。这样一来就出现了一个鸡生单还是蛋生鸡的问题,这个 AppDomain.CreateDomain 方法肯定是要在一个载入了 AppDomain 类型的 AppDomain 里面被调用的,但这个 AppDomain 又是谁调用 AppDomain.CreateDomain 方法创建的呢?呵呵   我们可以使用 WinDbg SOS 的 EEHeap 命令,通过列出 CLR 执行引擎的堆信息,获取当前运行的 AppDomain 情况。我们以下面这段代码为例   以下内容为程序代码:      //   // AppDomain.cs   //   using System;      public class EntryPoint   {   public static void Main(string[] args)   {   Console.Out.WriteLine("Hello AppDomain!";   Console.In.ReadLine();   }   }      这个典型的 CLR 程序的输出如下:      以下为引用:      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)      我们可以看到,虽然这个程序非常简单,没有自己创建任何 AppDomain,但实际上 CLR 已经有了三个 AppDomain:"System Domain", "Shared Domain" 和 "Domain 0"。而进一步使用 DumpDomain 命令查看三个 AppDomain:      以下为引用:      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   LowFrequencyHeap: 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      我们可以看到,System Domain 实际上是专门用于载入 mscorlib.dll 这个 BCL 基础库的;Shared Domain 暂时没有使用;而 Domain 0 则负责运行我们的目标 Assembly。我们可以猜测 System Domain 是 CLR 专门用来载入系统基础库的,而系统将进一步使用此 mscorlib 创建其他 AppDomain 以运行用户目标 Assembly。我们接下来看看 Rotor 的相关代码,是否能够予以印证。   在 CLR 启动时负责加载执行引擎的 EEStartup 函数(vmceemain.cpp:206)中,可以发现此函数首先在进行基础性初始化工作后,调用 SystemDomain::Attach 函数载入 SystemDomain,然后加载并初始化异常处理、JITer等等支持代码,最后会调用 SystemDomain::Init 函数完成初始化 SystemDomain 等等工作。   SystemDomain::Attach 函数(vmappdomain.cpp:912)主要完成四部分工作:初始化系统 stub 管理器和 SystemDomain 的静态成员变量;以全局静态数组 g_pSystemDomainMemory 的内存区,构造并初始化 SystemDomain 对象,并将指针保存到 m_pSystemDomain 静态变量中,用于以后判断 SystemDomain 是否被构造等功能使用;构造缺省的 AppDomain;构造 SharedDomain。函数的简要功能代码如下:   以下内容为程序代码:      SystemDomain*    SystemDomain::m_pSystemDomain = NULL;   static BYTE     g_pSystemDomainMemory[sizeof(SystemDomain)];      HRESULT SystemDomain::Attach()   {   // 判断 SystemDomain 是否已经构造   _ASSERTE(m_pSystemDomain == NULL);   if(m_pSystemDomain != NULL)   return COR_E_EXECUTIONENGINE;      // 初始化系统 stub 管理器和 SystemDomain 的静态成员变量   // ...      // 构造 SystemDomain 对象   m_pSystemDomain = new (&g_pSystemDomainMemory) SystemDomain();   if(m_pSystemDomain == NULL) return COR_E_OUTOFMEMORY;      // 初始化 SystemDomain 对象   HRESULT hr = m_pSystemDomain->BaseDomain::Init(); // Setup the memory heaps   if(FAILED(hr)) return hr;      m_pSystemDomain->GetInterfaceVTableMapMgr().SetShared();      // 构造缺省的 AppDomain   hr = m_pSystemDomain->CreateDefaultDomain();   if(FAILED(hr)) return hr;      // 构造 SharedDomain   hr = SharedDomain::Attach();      return hr;   }      值得注意的是,为了让 SystemDomain 的构造不会失败,SystemDomain 及其基类 BaseDomain 的构造函数都为空,而初始化代码放到 Init 方法中完成,CLR 中很多类型的代码都使用类似的模式将构造和初始化分离以保障构造成功。BaseDomain::Init 函数在 SystemDomain::Attach 中直接被调用以初始化 SystemDomain 的父类;SystemDomain::Init 函数则在上面提到的 EEStartup 函数末尾才被调用,待会再详细讨论。   BaseDomain::Init 函数(vmappdomain.cpp:310)除了要负责初始化 BaseDomain 对象的一大堆成员变量外,主要负担堆和缓存的初始化。CLR 中的堆,实际上是在每个 AppDomain 中存在的,这也是为什么我们刚刚可以使用 EEHeap 命令列举 AppDomain 的原因。在初始化 BaseDomain 之后,会将 SystemDomain 的接口 VTable 映射表设置为共享,这是因为 SystemDomain 负责载入的 mscorlib 中类型实际上是所以 AppDomain 中都需要使用到的。   接着 SystemDomain::Attach 会调用 SystemDomain::CreateDefaultDomain 函数(vmappdomain.cpp:2522)构造缺省的 AppDomain,也就是前面试验中的 "Domain 0",用作载入用户指定 Assembly 执行。此函数只是简单地调用 SystemDomain::NewDomain 函数以非 Managed 方式构造新的 AppDomain 实例;然后将此 AppDomain 设置为缺省的 AppDomain。   以下内容为程序代码:      HRESULT SystemDomain::CreateDefaultDomain()   {   HRESULT hr = S_OK;      // 防止多次初始化   if (m_pDefaultDomain != NULL)   return S_OK;      // 以非 Managed 方式构造新的 AppDomain 实例   AppDomain* pDomain = NULL;   if (FAILED(hr = NewDomain(&pDomain)))   return hr;      // 将此 AppDomain 设置为缺省的 AppDomain   pDomain->GetSecurityDescriptor()->SetDefaultAppDomainProperty();      m_pDefaultDomain = pDomain;      // ...   }      SystemDomain::NewDomain 函数(vmappdomain.cpp:2480)比较简单,构造 AppDomain 实例后,通知此 <
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表