WinDbg探究CLR底层(1) - 应用程序域
一、什么是应用程序域
操作系统由于其稳定性与可靠性的要求,都会使用隔离层,来确保运行在某个隔离层内的代码不会对其他隔扇层的代码产生影响。如windows通过进程来实现这种隔离机制,所能的可执行代码、数据、以及其它资源都被包含在进程中,系统其他进程通常不允许对它们进行访问。同理、.net应用程序同样也是被局限在进程内执行,但是.net还进一步引入了另一种逻辑隔离层,也就是我们这里说的应用程序域(appdomain)。
二、如何查看应用程序域
下面用一个例子看看应用程序域:
using system; namespace sample01 { class program { static void main(string[] args) { console.writeline("hello world"); console.readline(); } } }
这段代码是一个简单的控制台程序,没有任何逻辑。运行起来,使用windbg附加到进程,然后执行以下命令:
0:006> .load sos 0:006> !eeversion *** error: symbol file could not be found. defaulted to export symbols for c:\windows\microsoft.net\framework\v4.0.30319\clr.dll - pdb symbol for clr.dll not loaded 4.7.3190.0 retail workstation mode sos version: 4.6.1648.0 retail build 0:006> !dumpdomain the version of sos does not match the version of clr you are debugging. please load the matching version of sos for the version of clr you are debugging. clr version: 4.7.3190.0 sos version: 4.6.1648.0 -------------------------------------- system domain: 7230d5a8 lowfrequencyheap: 7230d8cc highfrequencyheap: 7230d918 stubheap: 7230d964 stage: open name: none -------------------------------------- shared domain: 7230d258 lowfrequencyheap: 7230d8cc highfrequencyheap: 7230d918 stubheap: 7230d964 stage: open name: none assembly: 00cb30e8 [c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll] classloader: 00cb2bd0 module name 6a681000 c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll -------------------------------------- domain 1: 00c7f090 lowfrequencyheap: 00c7f4fc highfrequencyheap: 00c7f548 stubheap: 00c7f594 stage: open securitydescriptor: 00c87cb0 name: sample01.exe assembly: 00cb30e8 [c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll] classloader: 00cb2bd0 securitydescriptor: 00cb3060 module name 6a681000 c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll assembly: 00cb6718 [e:\workspace\dotnet\windbginspectclr\sample01\bin\debug\sample01.exe] classloader: 00cb6c18 securitydescriptor: 00cb6b90 module name 00be401c e:\workspace\dotnet\windbginspectclr\sample01\bin\debug\sample01.exe
通过!dumpdomain
命令输出,可以看到,这个示例执行程序所在进程中3个应用程序域,system、shared、domain 1。其中,domain 1是默认的应用程序域,它的名字就是映像本身的名字(sample01.exe)。
在每个应用程序域的输出消息中包含以下内容:
-
system domain: 指向应用程序域的指针。这个指针可以作为dumpdomain命令的输入参数,以得到指定应用程序域的信息,如:
0:006> !dumpdomain 7230d5a8 the version of sos does not match the version of clr you are debugging. please load the matching version of sos for the version of clr you are debugging. clr version: 4.7.3190.0 sos version: 4.6.1648.0 -------------------------------------- system domain: 7230d5a8 lowfrequencyheap: 7230d8cc highfrequencyheap: 7230d918 stubheap: 7230d964 stage: open name: none
lowfrequencyheap、highfrequencyheap、stubheap:.net程序是建立在中间语言(il)的基础上的,因此,每个应用程序域都有相就的msil代码。在jit编译成msil过程中,jit编译器需要保存与编译过程相关的数据,如机器代码与方法表(method table)等。因此,每个应用程序域都需要创建一定数据的堆(heap)来存储这些数据。lowfrequencyheap中则保存的是一些更新、访问较少的数据,highfrequencyheap包含的是被访问频繁的数据,而stubheap中包含的是clr执行互用性调用 (例如com互用性或者平台调用)时需要的辅助数据。
name:应用程序域名称。
assembly:在应用程序域中加载的所有程序集。从输出中来看,应用程序域sample01.exe中加载了两个程序集:mscorlib.dll、sample01.exe。其中更包含程序集版本、底层程序集数据结构地址,如sample01.exe程序集的地址为
00c7f090
。
三、各应用程序域的作用
系统应用程序域
- 创建其他两个应用程序域(共享应用程序域和默认应用程序域)。
- 将mscorlib.dll加载到共享应用程序域中(在下面将进一步讨论)。
- 记录进程中所有其他的应用程序域,包括提供加载/卸载应用程序域等功能。
- 记录字符串池中的字符串常量,因此允许任意字符串在每个进程中都存在一个副本。
- 初始化特定类型的异常,例如内存耗尽异常,栈溢出异常以及执行引擎异常等。
共享应用程序域
在共享应用程序域中包含的是与应用程序域无关的代码。mscorlib.dll将被加载到这个应用程序域中(由系统应用程序域负责加载),此外还包括在system命名空间中的一些基本类型(例如string、enum、valuetype、array等)。在大多数情况下,非用户代码(non-user code)将被加载到共享应用程序域中,不过也有一些机制可以将用户代码(user code)加载到共享应用程序域中。启用了clr的应用程序域可以通过加载器的优化属性来注入用户代码。
默认应用程序域
通常,.net程序在默认应用程序域中运行。位于默认应用程序域中的所有代码都只有在这个域中才是有效的。由于应用程序域实现了一种有逻辑并且可靠的边界,因此任何跨越应用程序域的访问操作都必须通过.net远程对象来进行。
四、动态创建、卸载应用程序域
前面我们看到程序启动时,系统帮我们创建的默认应用程序域,然后手动创建应用程序域也是可以的,代码如下:
using system; namespace sample02 { class program { static void main(string[] args) { console.writeline("before createdomain"); console.readline(); appdomain domain = appdomain.createdomain("newdomain"); console.writeline("after createdomain, before unload"); console.readline(); appdomain.unload(domain); console.writeline("after unload"); console.readline(); } } }
程序开始运行时:
有三个应用程序域:system domain、shared domain、domain 1
0:006> !dumpdomain -------------------------------------- system domain: 7230d5a8 lowfrequencyheap: 7230d8cc highfrequencyheap: 7230d918 stubheap: 7230d964 stage: open name: none -------------------------------------- shared domain: 7230d258 lowfrequencyheap: 7230d8cc highfrequencyheap: 7230d918 stubheap: 7230d964 stage: open name: none assembly: 00df8468 [c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll] classloader: 00df8520 module name 6a681000 c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll -------------------------------------- domain 1: 00dd7da0 lowfrequencyheap: 00dd820c highfrequencyheap: 00dd8258 stubheap: 00dd82a4 stage: open securitydescriptor: 00dd0120 name: sample02.exe assembly: 00df8468 [c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll] classloader: 00df8520 securitydescriptor: 00dfc018 module name 6a681000 c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll assembly: 00dff8d8 [e:\workspace\dotnet\windbginspectclr\sample02\bin\debug\sample02.exe] classloader: 00dff318 securitydescriptor: 00dfcd60 module name 00ec401c e:\workspace\dotnet\windbginspectclr\sample02\bin\debug\sample02.exe
按enter
继续执行,多一个应用程序域domain 2
0:006> !dumpdomain the version of sos does not match the version of clr you are debugging. please load the matching version of sos for the version of clr you are debugging. clr version: 4.7.3190.0 sos version: 4.6.1648.0 -------------------------------------- system domain: 7230d5a8 lowfrequencyheap: 7230d8cc highfrequencyheap: 7230d918 stubheap: 7230d964 stage: open name: none -------------------------------------- shared domain: 7230d258 lowfrequencyheap: 7230d8cc highfrequencyheap: 7230d918 stubheap: 7230d964 stage: open name: none assembly: 00df8468 [c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll] classloader: 00df8520 module name 6a681000 c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll -------------------------------------- domain 1: 00dd7da0 lowfrequencyheap: 00dd820c highfrequencyheap: 00dd8258 stubheap: 00dd82a4 stage: open securitydescriptor: 00dd0120 name: sample02.exe assembly: 00df8468 [c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll] classloader: 00df8520 securitydescriptor: 00dfc018 module name 6a681000 c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll assembly: 00dff8d8 [e:\workspace\dotnet\windbginspectclr\sample02\bin\debug\sample02.exe] classloader: 00dff318 securitydescriptor: 00dfcd60 module name 00ec401c e:\workspace\dotnet\windbginspectclr\sample02\bin\debug\sample02.exe -------------------------------------- domain 2: 00e0cf00 lowfrequencyheap: 00e0d36c highfrequencyheap: 00e0d3b8 stubheap: 00e0d404 stage: open securitydescriptor: 00e09fe0 name: newdomain assembly: 00df8468 [c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll] classloader: 00df8520 securitydescriptor: 00dfccd8 module name 6a681000 c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll assembly: 00e17398 [e:\workspace\dotnet\windbginspectclr\sample01\bin\debug\sample01.exe] classloader: 00e21d90 securitydescriptor: 00dfc128 module name 011949f4 e:\workspace\dotnet\windbginspectclr\sample01\bin\debug\sample01.exe
再次按enter
继续执行,应用程序域domain 2中的sample01.exe被卸载, 目前还没查到为什么domain 2 没被整体卸载,我猜想是因为mscorlib.dll还在还在使用。
0:006> !dumpdomain the version of sos does not match the version of clr you are debugging. please load the matching version of sos for the version of clr you are debugging. clr version: 4.7.3190.0 sos version: 4.6.1648.0 -------------------------------------- system domain: 7230d5a8 lowfrequencyheap: 7230d8cc highfrequencyheap: 7230d918 stubheap: 7230d964 stage: open name: none -------------------------------------- shared domain: 7230d258 lowfrequencyheap: 7230d8cc highfrequencyheap: 7230d918 stubheap: 7230d964 stage: open name: none assembly: 00aa7a90 [c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll] classloader: 00aa8818 module name 6a681000 c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll -------------------------------------- domain 1: 00a7f410 lowfrequencyheap: 00a7f87c highfrequencyheap: 00a7f8c8 stubheap: 00a7f914 stage: open securitydescriptor: 00a869f0 name: sample02.exe assembly: 00aa7a90 [c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll] classloader: 00aa8818 securitydescriptor: 00aa7a08 module name 6a681000 c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll assembly: 00aab3b8 [e:\workspace\dotnet\windbginspectclr\sample02\bin\debug\sample02.exe] classloader: 00aab050 securitydescriptor: 00aab5f0 module name 0097401c e:\workspace\dotnet\windbginspectclr\sample02\bin\debug\sample02.exe -------------------------------------- domain 2: 00ab93d8 lowfrequencyheap: 00ab9844 highfrequencyheap: 00ab9890 stubheap: 00ab98dc stage: handletable_noaccess name: newdomain assembly: 00aa7a90 [c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll] classloader: 00aa8818 securitydescriptor: 00abd780 module name 6a681000 c:\windows\microsoft.net\assembly\gac_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll assembly: 00acdce0 [] classloader: 00acde80 securitydescriptor: 00abcb48 module name 04cf49f4 dynamic module
六、总结
一直听说应用程序域,但对其概念、作用不甚了解,因此结合windbg来试图对其进行深入理解,加深印象,后续系列会继续使用windbg对clr底层进行研究。
参考文献
下一篇: 前端工作面试问题(上)