CLR探索应用程序域世界(上):Windbg SOS剖析揭示域世界
在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:/Projects/TestConcoleApp/TestConcoleApp/bin/Debug/TestConcoleApp.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:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/Temporary ASP.NETFiles/mesapplication/8a8504fd/e1680364
C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/Temporary ASP.NET Files/mesapplication这一部分,由一个叫做DYNAMIC_BASE的属性来定义。同时包含了这个应用程序域中加载的项目文件信息。
后面的两部分8a8504fd/e1680364,根据项目文件的不同,由应用程序的APP_NAME这个属性来决定。
这样何在一起,就构成了在调试的过程中,进程在本机的缓存文件夹。
CLR探索应用程序域世界(上):Windbg SOS剖析揭示域世界的更多相关文章
- CLR探索系列:Windbg+SOS动态调试分析托管代码
http://blog.csdn.net/garyye/article/details/4788070 在使用VS进行托管应用程序的调试的时候,有的时候总感觉有些力不从心.譬如查看一个托管堆或者计 ...
- WinDbg 命令三部曲:(二)WinDbg SOS 扩展命令手册
本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 系列博文 <WinDbg 命令三部曲:(一)WinDbg 命令手册> <WinDb ...
- 用windbg+sos找出程序中谁占用内存过高,谁占用CPU过高(转载)
原文地址: http://www.cnblogs.com/Lawson/archive/2011/01/23/1942692.html 很早看到windbg+sos方面的知识,一直没仔细学习,也许因为 ...
- windbg sos版本不匹配问题解决
dumpheap 时提示: 0:105> !dumpheap -stat The garbage collector data structures are not in a valid sta ...
- 带你剖析WebGis的世界奥秘----Geojson数据加载(高级)(转)
带你剖析WebGis的世界奥秘----Geojson数据加载(高级) 转:https://zxhtom.oschina.io/zxh/20160819.html 编程 java 2016/08/ ...
- 带你剖析WebGis的世界奥秘----点和线的世界(转)
带你剖析WebGis的世界奥秘----点和线的世界 转:https://zxhtom.oschina.io/zxh/20160813.html 编程 java 2016/08/13 0留言, 0 ...
- 带你剖析WebGis的世界奥秘----瓦片式加载地图(转)
带你剖析WebGis的世界奥秘----瓦片式加载地图 转:https://zxhtom.oschina.io/zxh/20160805.html 编程 java 2016/08/05 0留言, ...
- 为什么我会认为SAP是世界上最好用最牛逼的ERP系统,没有之一?
为什么我认为SAP是世界上最好用最牛逼的ERP系统,没有之一?玩过QAD.Tiptop.用友等产品,深深觉得SAP是贵的有道理! 一套好的ERP系统,不仅能够最大程度承接适配企业的管理和业务流程,在技 ...
- Nivo Slider - 世界上最棒的 jQuery 图片轮播插件
Nivo Slider 号称世界上最棒的图片轮播插件,有独立的 jQuery 插件和 WordPress 插件两个版本.目前下载量已经突破 1,800,000 次!jQuery 独立版本的插件主要有如 ...
随机推荐
- 对象不支持“attachEvent”属性或方法的解决办法
有些脚本在IE11下执行会报错误: 对象不支持“attachEvent”属性或方法 解决办法 解决办法:把attachEvent改为addEventListener即可
- BZOJ_1624_ [Usaco2008_Open]_Clear_And_Present_Danger_寻宝之路_(最短路_Floyd)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1025 给出\(n\)个点以及之间的边的长度,给出必须访问的点的顺序,求最短路线长度. 分析 用 ...
- Android基础_3 Activity相对布局
相对布局要比前面讲的线性布局和表格布局要灵活一些,所以平常用得也是比较多的.相对布局控件的位置是与其周围控件的位置相关的,从名字可以看出来,这些位置都是相对的,确定出了其中一个控件的位置就可以确定另一 ...
- <摘录>PS和TS流的区别
在 MPEG-2系统中,信息复合/分离的过程称为系统复接/分接,由视频,音频的ES流和辅助数据复接生成的用于实际传输的标准信息流称为MPEG-2传送 流(TS:TransportStream).据传输 ...
- Android02--debug.keystore的注册信息
1 -- 签名文件的密钥 默认签名文件的密码是:android 该文件的存放点是: 2 -- 签名文件的签名信息 keytool -list -v -keystore C:\Users\motadou ...
- MyBatis一对多双向关联——MyBatis学习笔记之七
处理has-one关系需要用到association元素,而处理has many关系则需要用到collection元素.例如本例中,假设一 名教师可同时指导多名学生,下面就来介绍如何使用collect ...
- JUC之Atomic系列12大类实例讲解和原理分解
在java6以后我们不但接触到了Lock相关的锁,也接触到了很多更加乐观的原子修改操作,也就是在修改时我们只需要保证它的那个瞬间是安全的即可,经过相应的包装后可以再处理对象的并发修改,以及并发中的AB ...
- linux常用命令之--目录与文件的操作命令
1.linux的目录与文件的增.删.改.复制 pwd:用于显示当前所在的目录 ls:用于显示指定目录下的内容 其命令格式如下: ls [-option] [file] 常用参数: -l:显示文件和目录 ...
- ADO.NET 中的数据并发
当多个用户试图同时修改数据时,需要建立控制机制来防止一个用户的修改对同时操作的其他用户所作的修改产生不利的影响.处理这种情况的系统叫做“并发控制”.并发控制的类型通常,管理数据库中的并发有三种常见的方 ...
- const 常量数据,只读
网上其他的博客地址:1 http://www.cnblogs.com/ronny/p/3672501.html 2 http://www.cnblogs.com/hellogiser/p/cplusp ...