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 独立版本的插件主要有如 ...
随机推荐
- 在win7系统下使用TortoiseGit(乌龟git)简单操作Git@OSC
非常感谢OSC提供了这么好的一个国内的免费的git托管平台.这里简单说下TortoiseGit操作的流程.很傻瓜了 首先你要准备两个软件,分别是msysgit和tortoisegit,乌龟还可以在下载 ...
- UVALive 2238 Fixed Partition Memory Management(二分完美匹配)
题意:计算机中有一些固定大小的内存,内存越大,处理速度越快.对于一个程序,加入不同的内存空间,处理所需时间不同.现给出m个内存空间,n个程序,对于每个程序程序,有k组数据(s,t),分别表示当程序 i ...
- Java [Leetcode 235]Lowest Common Ancestor of a Binary Search Tree
题目描述: Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in ...
- 【原创】回溯线搜索 Backtracking line search
机器学习中很多数值优化算法都会用到线搜索(line search).线搜索的目的是在搜索方向上找到是目标函数\(f(x)\)最小的点.然而,精确找到最小点比较耗时,由于搜索方向本来就是近似,所以用较小 ...
- poj 3160 Father Christmas flymouse
// 题目描述:从武汉大学ACM集训队退役后,flymouse 做起了志愿者,帮助集训队做一些琐碎的事情,比如打扫集训用的机房等等.当圣诞节来临时,flymouse打扮成圣诞老人给集训队员发放礼物.集 ...
- 【DFS+记忆搜索】NYOJ-10-Skiing
[题目链接:NYOJ-10] skiing 时间限制:3000 ms | 内存限制:65535 KB 难度:5 描述 Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑 ...
- Oracle权限一览表
权限 所能实现的操作 分析 ANALYZE ANY 分析数据库中的任何表.簇或索引 审计 AUDIT ANY 审计数据库中的任何模式对象 AUDIT SYSTEM 启用与停用语句和特权的审计选项 ...
- Autofac 依赖注入 ASP.NET MVC5 插件机制中插件的简单实现
一.前言 由于项目业务复杂,创建了多个插件并把他们放在了不同的项目中,项目使用AutoFac做的IOC:但是主项目可以注入,插件注入失败, 没有为该对象定义无参数的构造函数.下面就一步一步注入插件项目 ...
- hdu 1078(dfs记忆化搜索)
题意:容易理解... 思路:我开始是用dfs剪枝做的,968ms险过的,后来在网上学习了记忆化搜索=深搜形式+dp思想,时间复杂度大大降低,我个人理解,就是从某一个点出发,前面的点是由后面的点求出的, ...
- Conversion to Dalvik format failed: Unable to execute dex: null
[2013-11-19 14:18:48 - Dex Loader] Unable to execute dex: java.nio.BufferOverflowException. Check th ...