CLR探索系列之应用程序域世界(上):Windbg+SOS剖析揭示域世界
点击次数:22 次 发布日期:2008-11-26 10:33:27 作者:源代码网
|
源代码网推荐 在CLR的世界中,有一系列的令人Amazing的技术和架构。其中,CLR对应用程序在内存中内存分配,执行模型,程序之间的交互等一系列的技术,值得每一个致力于DotNet平台的技术人员深究。 源代码网推荐 编程人员在开发的过程中,如果把程序集的加载(Assemblies Load),反射(Reflection),寄宿(Hosting),应用程序域(AppDomain),这四种技术结合起来使用的话,不仅能更好的使用CLR这个平台提供的强大的功能,而且能够构建更安全,更健壮的应用程序代码。 源代码网推荐 源代码网推荐 这篇博文里,就是使用托管代码的动态调试工具,来研究一下CLR内部AppDomain的世界。 源代码网推荐 源代码网推荐 首先,从一个C#程序开始: 源代码网推荐 class Program 源代码网推荐 { 源代码网推荐 static void Main(string[] args) 源代码网推荐 { 源代码网推荐 Program b = new Program(); 源代码网推荐 b.test(); 源代码网推荐 System.Console.ReadLine(); 源代码网推荐 } 源代码网推荐 源代码网推荐 public void test() 源代码网推荐 { 源代码网推荐 int i = 67; 源代码网推荐 System.Console.WriteLine((char)i); 源代码网推荐 System.Console.WriteLine((char)67); 源代码网推荐 i = 1; 源代码网推荐 } 源代码网推荐 } 源代码网推荐 源代码网推荐 运行了这个应用程序以后,我们打开windbg,attach到这个托管进程。 源代码网推荐 .load SOS 源代码网推荐 加载SOS扩展调试模块,可以使用.chain指令查看加载是否正确。 源代码网推荐 0:003> lm 源代码网推荐 start end module name 源代码网推荐 00400000 00408000 TestConcoleApp (deferred) 源代码网推荐 76990000 76acd000 ole32 (deferred) 源代码网推荐 77be0000 77c38000 msvcrt (deferred) 源代码网推荐 省略若干 源代码网推荐 77fc0000 77fd1000 Secur32 (deferred) 源代码网推荐 78130000 781cb000 MSVCR80 (deferred) 源代码网推荐 79000000 79045000 mscoree (deferred) 源代码网推荐 79060000 790b3000 mscorjit (deferred) 源代码网推荐 790c0000 79b90000 mscorlib_ni (deferred) 源代码网推荐 79e70000 7a3d6000 mscorwks (deferred) 源代码网推荐 查看下意境加载了的模块,然后使用ld命令把我们的调试符号文件载入。VS在编译生成一个Console App的时候,在debug模式的时候会在debug的bin目录下生成一个和应用程序同名的pdb文件。我们要做的,就是载入这个文件: 源代码网推荐 源代码网推荐 0:003> ld TestConcoleApp 源代码网推荐 *** WARNING: Unable to verify checksum for G:ProjectsTestConcoleAppTestConcoleAppinDebugTestConcoleApp.exe 源代码网推荐 Symbols loaded for TestConcoleApp 源代码网推荐 源代码网推荐 有一个警告,咋这里先不管,再使用lm查看已经加载了的模块的时候,可以看到这个module的调试符号文件已经被加载上了。 源代码网推荐 源代码网推荐 此时,我们可以查看下Excute Engine (CLR)的堆里面都有些什么东西,我们可以使用!EEHeap命令,EE的意思,就是CLI的执行引擎,也就是我们常说的CLR。这个命令可以查看到一个托管进程里面的garbage-collected 和 Loader heaps相关信息。 源代码网推荐 0:003> !eeheap 源代码网推荐 PDB symbol for mscorwks.dll not loaded 源代码网推荐 Loader Heap: 源代码网推荐 -------------------------------------- 源代码网推荐 System Domain: 7a38f918 源代码网推荐 LowFrequencyHeap: Size: 0x0(0)bytes. 源代码网推荐 HighFrequencyHeap: 00a62000(8000:1000) Size: 0x1000(4096)bytes. 源代码网推荐 StubHeap: 00a6a000(2000:1000) Size: 0x1000(4096)bytes. 源代码网推荐 Virtual Call Stub Heap: 源代码网推荐 IndcellHeap: Size: 0x0(0)bytes. 源代码网推荐 LookupHeap: Size: 0x0(0)bytes. 源代码网推荐 ResolveHeap: Size: 0x0(0)bytes. 源代码网推荐 DispatchHeap: Size: 0x0(0)bytes. 源代码网推荐 CacheEntryHeap: Size: 0x0(0)bytes. 源代码网推荐 Total size: 0x2000(8192)bytes 源代码网推荐 /********************************************** 源代码网推荐 Loader Heap 中的系统域。这个域和下面的Shared Domian一起,是对托管的宿主程序,以及托管代码不可见的。这个域加载了两个CLR执行中十分重要的Module,MSCorEE.dll和MScorwks.dll。MSCorEE.dll这个文件就是大家熟悉的shim,垫片。在CLR加载中起到的重要作用。这里就不分析了,大家可以参考别的文献的介绍。 源代码网推荐 对于每个应用程序域,都会有自己的安全描述符,安全上下文以及默认的上下文。这三个部分可以支持一个应用程序域来自定义一个单独实施的安全策略,譬如,可以用来确保宿主程序在加载托管代码的时候不会对这些重要的数据结构造成破坏。 源代码网推荐 **********************************************/ 源代码网推荐 -------------------------------------- 源代码网推荐 Shared Domain: 7a38fef0 源代码网推荐 LowFrequencyHeap: 00a90000(2000:1000) Size: 0x1000(4096)bytes. 源代码网推荐 HighFrequencyHeap: Size: 0x0(0)bytes. 源代码网推荐 StubHeap: 00a9a000(2000:1000) Size: 0x1000(4096)bytes. 源代码网推荐 Virtual Call Stub Heap: 源代码网推荐 IndcellHeap: Size: 0x0(0)bytes. 源代码网推荐 LookupHeap: Size: 0x0(0)bytes. 源代码网推荐 ResolveHeap: 00aab000(5000:1000) Size: 0x1000(4096)bytes. 源代码网推荐 DispatchHeap: 00aa7000(4000:1000) Size: 0x1000(4096)bytes. 源代码网推荐 CacheEntryHeap: Size: 0x0(0)bytes. 源代码网推荐 Total size: 0x4000(16384)bytes 源代码网推荐 /********************************************** 源代码网推荐 在共享域中,加载所有的应用程序域中都要使用到的assemblies,譬如MScorlib.dll。装载了System.Object,System.ValueType这样的基础类。 源代码网推荐 **********************************************/ 源代码网推荐 -------------------------------------- 源代码网推荐 Domain 1: 154250 源代码网推荐 LowFrequencyHeap: 00a70000(2000:2000) Size: 0x2000(8192)bytes. 源代码网推荐 HighFrequencyHeap: 00a72000(8000:2000) Size: 0x2000(8192)bytes. 源代码网推荐 StubHeap: Size: 0x0(0)bytes. 源代码网推荐 Virtual Call Stub Heap: 源代码网推荐 IndcellHeap: Size: 0x0(0)bytes. 源代码网推荐 LookupHeap: Size: 0x0(0)bytes. 源代码网推荐 ResolveHeap: Size: 0x0(0)bytes. 源代码网推荐 DispatchHeap: Size: 0x0(0)bytes. 源代码网推荐 CacheEntryHeap: Size: 0x0(0)bytes. 源代码网推荐 Total size: 0x4000(16384)bytes 源代码网推荐 /********************************************** 源代码网推荐 对于特定的寄宿程序,可以根据需要创建多个应用的默认域。例如IE,Asp.Net,或者是SqlServer,可以创建一个或者是多个默认的域。域名默认情况下的name就是module的名称。 源代码网推荐 在默认域中,应用程序执行的时候需要装载经来的assemblies可以被加载到这里。 源代码网推荐 在每个应用程序域中,代码创建的对象不能直接访问另外的应用程序域中的代码。如果要访问这些代码,可以采用静态的委托,或者是appDomain的自己的方法来实现。 源代码网推荐 **********************************************/ 源代码网推荐 -------------------------------------- 源代码网推荐 Jit code heap: 源代码网推荐 LoaderCodeHeap: 00db0000(10000:1000) Size: 0x1000(4096)bytes. 源代码网推荐 Total size: 0x1000(4096)bytes 源代码网推荐 对于托管的应用程序,有两种把IL代码编译成本地代码的方式。一种是在第一次运行的时候,调用JIT模块来实时编译,编译好了的本地代码就放到这里。在PE文件中的相应的代码处,就用一个指针指引CLR到这里来找相关的编译好了的本地代码。第二中是安装的时候就编译成为本地代码。 源代码网推荐 同时可以看到,Jit Heap占用很少的内存空间。 源代码网推荐 -------------------------------------- 源代码网推荐 Module Thunk heaps: 源代码网推荐 Module 790c2000: Size: 0x0(0)bytes. 源代码网推荐 Module 00a72c24: Size: 0x0(0)bytes. 源代码网推荐 Total size: 0x0(0)bytes 源代码网推荐 -------------------------------------- 源代码网推荐 Module Lookup Table heaps: 源代码网推荐 Module 790c2000: Size: 0x0(0)bytes. 源代码网推荐 Module 00a72c24: Size: 0x0(0)bytes. 源代码网推荐 Total size: 0x0(0)bytes 源代码网推荐 源代码网推荐 -------------------------------------- 源代码网推荐 Total LoaderHeap size: 0xb000(45056)bytes 源代码网推荐 总共的loader Heap的大小大概在45kb左右。 源代码网推荐 ======================================= 源代码网推荐 Number of GC Heaps: 1 源代码网推荐 generation 0 starts at 0x013b1018 源代码网推荐 generation 1 starts at 0x013b100c 源代码网推荐 generation 2 starts at 0x013b1000 源代码网推荐 ephemeral segment allocation context: none 源代码网推荐 下面的这两个segment对于应用程序域的其他代码来说是read only的,所以,这两部分的空间比较小。这块经常保存的是小的segement片段。除非你是很长很长的字符串。而大的object,则保持在LOH中。GC Heap,可以有多个。每个GC Heap中,都可以有一个LOH。 源代码网推荐 而每个GC Heap的总大小=Segment占用的空间+LOH 源代码网推荐 segment begin allocated size 源代码网推荐 0014d720 790d5588 790f4b38 0x0001f5b0(128432) 源代码网推荐 013b0000 013b1000 013b3ff4 0x00002ff4(12276) 源代码网推荐 Large object heap starts at 0x023b1000 源代码网推荐 segment begin allocated size 源代码网推荐 023b0000 023b1000 023b3250 0x00002250(8784) 源代码网推荐 Total Size 0x247f4(149492) 源代码网推荐 ------------------------------ 源代码网推荐 GC Heap Size 0x247f4(149492) 源代码网推荐 总共的GC堆大概150kb。 源代码网推荐 --------------------------------------------------------------------------------------------------------- 源代码网推荐 托管线程的内存结构: 源代码网推荐 这里,简单的交代一下一个托管进程的内存结构。在创建了一个托管的应用程序的线程以后,首先默认情况下创建了最少3个应用程序域,就是系统域,共享域,和默认域。前两个对托管的用户代码来说是不可见的。当时,可以调用共享与中的assemblies。用户的托管代码,和模块被load到默认域中。一个托管的宿主可以根据需要创建一个或者是多个默认域。 源代码网推荐 源代码网推荐 托管进程,线程(hard thread,soft thread),应用程序域,程序集,模块的关系 源代码网推荐 托管进程,应用程序域,程序集,模块,这四个概念从左到右是一对多的关系。及一个托管可以对应多个应用程序域,一个appdomain可以对应多个assemblies,一个assembly可以对应多个modules。modules就是我们经常看的.exe或者是.dll。exe文件是windows下对PE文件格式扩展了的托管模块。modules也可以是托管的动态链接库文件。 源代码网推荐 对于线程,情况有点特殊。这里,首先要区别一个概念,操作系统的进程创建的线程和System.Threading.Thread这个类表示的线程。这里,把操作系统创建的进程叫做hard thread,System.Threading.Thread这个类表示的线程叫做soft Thread。hard Thread和应用程序域的关系,是多堆多的关系。就是一个应用程序域中可以存在多个hard Thread。而一个hard Thread,也可以存在于多个应用程序域里面。而soft Thread,是由应用程序域中的assemblies创建,所以,它只存在于相应的应用程序域中。 源代码网推荐 当一个系统的hard thread进入某个应用程序域中进行操作的时候,这个应用程序域就会实例化一个System.Threading.Thread类来完成这个线程对应的工作。 源代码网推荐 源代码网推荐 应用程序域的环境变量属性: 源代码网推荐 对于每个应用程序域,有一系列的Environment属性可以设置,通过设置这些属性,可以配置一个应用程序域的特性,来满足各种对于安全,性能等许多方面特别的需求。 源代码网推荐 可以参考MSDN的这里: 源代码网推荐 http://msdn2.microsoft.com/en-us/library/system.appdomain_properties.aspx 源代码网推荐 获知应用程序域相关的所有的Properties。 源代码网推荐 特别说明:应用程序域的动态目录: 源代码网推荐 对于应用程序域的所有的属性,需要特别提到一个叫做DynamicDirectory 的属性。 源代码网推荐 这个属性的生成,有两个部分,譬如我本机上面的一个asp.net宿主进程的缓存文件夹: 源代码网推荐 C:WINDOWSMicrosoft.NETFrameworkv2.0.50727Temporary ASP.NET Filesmesapplication8a8504fde1680364 源代码网推荐 C:WINDOWSMicrosoft.NETFrameworkv2.0.50727Temporary ASP.NET Filesmesapplication这一部分,由一个叫做DYNAMIC_BASE的属性来定义。同时包含了这个应用程序域中加载的项目文件信息。 源代码网推荐 后面的两部分8a8504fde1680364,根据项目文件的不同,由应用程序的APP_NAME这个属性来决定。 源代码网推荐 这样何在一起,就构成了在调试的过程中,进程在本机的缓存文件夹。 源代码网推荐 源代码网推荐 在接下来的下篇中,讲从如何实现的角度,以实例源代码来分析AppDomain的运行机制。 源代码网推荐 源代码网推荐 源代码网推荐 做人要厚道,请注明转自酷网动力(www.ASPCOOL.COM)。 源代码网推荐 源代码网供稿. |
