扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
本篇文章给大家分享的是有关CLR是怎么创建运行时对象,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。
创新互联专注于源城企业网站建设,成都响应式网站建设公司,成都做商城网站。源城网站建设公司,为源城等地区提供建站服务。全流程按需开发,专业设计,全程项目跟踪,创新互联专业和态度为您提供的服务原文地址:
原文发布日期: 9/19/2005
原文已经被 Microsoft 删除了,收集过程中发现很多文章图都不全,那是因为原文的图都不全,所以特收集完整全文。
前言
CLR启动程序(Bootstrap)创建的域
系统域(System Domain)
共享域(Shared Domain)
默认域(Default Domain)
加载器堆(Loader Heaps)
类型原理
对象实例
方法表
基实例大小
方法槽表(Method Slot Table)
方法描述(MethodDesc)
接口虚表图和接口图(Interface Vtable Map and Interface Map)
虚分派(Virtual Dispatch)
静态变量(Static Variables)
EEClass
结论
SystemDomain, SharedDomain, and DefaultDomain。
对象布局和内存细节。
方法表布局。
方法分派(Method dispatching)。
因为公共语言运行时(CLR)即将成为在Windows上创建应用程序的主角级基础架构, 多掌握点关于CLR的深度认识会帮助你构建高效的, 工业级健壮的应用程序. 在这篇文章中, 我们会浏览,调查CLR的内在本质, 包括对象实例布局, 方法表的布局, 方法分派, 基于接口的分派, 和各种各样的数据结构.
我们会使用由C#写成的非常简单的代码示例, 所以任何对编程语言的隐式引用都是以C#语言为目标的. 讨论的一些数据结构和算法会在Microsoft® .NET Framework 2.0中改变, 但是绝大多数的概念是不会变的. 我们会使用Visual Studio® .NET 2003 Debugger和debugger extension Son of Strike (SOS)来窥视一些数据结构. SOS能够理解CLR内部的数据结构, 能够dump出有用的信息. 通篇, 我们会讨论在Shared Source CLI(SSCLI)中拥有相关实现的类, 你可以从 下载到它们.
图表1 会帮助你在搜索一些结构的时候到SSCLI中的信息.
ITEM | SSCLI PATH |
---|---|
AppDomain | sscliclrsrcvmappdomain.hpp |
AppDomainStringLiteralMap | sscliclrsrcvmstringliteralmap.h |
BaseDomain | sscliclrsrcvmappdomain.hpp |
ClassLoader | sscliclrsrcvmclsload.hpp |
EEClass | sscliclrsrcvmclass.h |
FieldDescs | sscliclrsrcvmfield.h |
GCHeap | sscliclrsrcvmgc.h |
GlobalStringLiteralMap | sscliclrsrcvmstringliteralmap.h |
HandleTable | sscliclrsrcvmhandletable.h |
InterfaceVTableMapMgr | sscliclrsrcvmappdomain.hpp |
Large Object Heap | sscliclrsrcvmgc.h |
LayoutKind | sscliclrsrcbclsystemruntimeinteropserviceslayoutkind.cs |
LoaderHeaps | sscliclrsrcincutilcode.h |
MethodDescs | sscliclrsrcvmmethod.hpp |
MethodTables | sscliclrsrcvmclass.h |
OBJECTREF | sscliclrsrcvmtypehandle.h |
SecurityContext | sscliclrsrcvmsecurity.h |
SecurityDescriptor | sscliclrsrcvmsecurity.h |
SharedDomain | sscliclrsrcvmappdomain.hpp |
StructLayoutAttribute | sscliclrsrcbclsystemruntimeinteropservicesattributes.cs |
SyncTableEntry | sscliclrsrcvmsyncblk.h |
System namespace | sscliclrsrcbclsystem |
SystemDomain | sscliclrsrcvmappdomain.hpp |
TypeHandle | sscliclrsrcvmtypehandle.h |
在我们开始前,请注意:本文提供的信息只对在X86平台上运行的.NET Framework 1.1有效(对于Shared Source CLI 1.0也大部分适用,只是在某些交互操作的情况下必须注意例外),对于.NET Framework 2.0会有改变,所以请不要在构建软件时依赖于这些内部结构的不变性。
在CLR执行托管代码的第一行代码前,会创建三个应用程序域。其中两个对于托管代码甚至CLR宿主程序(CLR hosts)都是不可见的。它们只能由CLR启动进程创建,而提供CLR启动进程的是shim——mscoree.dll和mscorwks.dll (在多处理器系统下是mscorsvr.dll)。正如 图2 所示,这些域是系统域(System Domain)和共享域(Shared Domain),都是使用了单件(Singleton)模式。第三个域是缺省应用程序域(Default AppDomain),它是一个AppDomain的实例,也是唯一的有命名的域。对于简单的CLR宿主程序,比如控制台程序,默认的域名由可执行映象文件的名字组成。其它的域可以在托管代码中使用AppDomain.CreateDomain方法创建,或者在非托管的代码中使用ICORRuntimeHost接口创建。复杂的宿主程序,比如 ASP.NET,对于特定的网站会基于应用程序的数目创建多个域。
图 2 由CLR启动程序创建的域 ↓
系统域负责创建和初始化共享域和默认应用程序域。它将系统库mscorlib.dll载入共享域,并且维护进程范围内部使用的隐含或者显式字符串符号。
字符串驻留(string interning)是 .NET Framework 1.1中的一个优化特性,它的处理方法显得有些笨拙,因为CLR没有给程序集机会选择此特性。尽管如此,由于在所有的应用程序域中对一个特定的符号只保存一个对应的字符串,此特性可以节省内存空间。
系统域还负责产生进程范围的接口ID,并用来创建每个应用程序域的接口虚表映射图(InterfaceVtableMaps)的接口。系统域在进程中保持跟踪所有域,并实现加载和卸载应用程序域的功能。
所有不属于任何特定域的代码被加载到系统库SharedDomain.Mscorlib,对于所有应用程序域的用户代码都是必需的。它会被自动加载到共享域中。系统命名空间的基本类型,如Object, ValueType, Array, Enum, String, and Delegate等等,在CLR启动程序过程中被预先加载到本域中。用户代码也可以被加载到这个域中,方法是在调用CorBindToRuntimeEx时使用由CLR宿主程序指定的LoaderOptimization特性。控制台程序也可以加载代码到共享域中,方法是使用System.LoaderOptimizationAttribute特性声明Main方法。共享域还管理一个使用基地址作为索引的程序集映射图,此映射图作为管理共享程序集依赖关系的查找表,这些程序集被加载到默认域(DefaultDomain)和其它在托管代码中创建的应用程序域。非共享的用户代码被加载到默认域。
默认域是应用程序域(AppDomain)的一个实例,一般的应用程序代码在其中运行。尽管有些应用程序需要在运行时创建额外的应用程序域(比如有些使用插件,plug-in,架构或者进行重要的运行时代码生成工作的应用程序),大部分的应用程序在运行期间只创建一个域。所有在此域运行的代码都是在域层次上有上下文限制。如果一个应用程序有多个应用程序域,任何的域间访问会通过.NET Remoting代理。额外的域内上下文限制信息可以使用System.ContextBoundObject派生的类型创建。每个应用程序域有自己的安全描述符(SecurityDescriptor),安全上下文(SecurityContext)和默认上下文(DefaultContext),还有自己的加载器堆(高频堆,低频堆和代理堆),句柄表,接口虚表管理器和程序集缓存。
加载器堆的作用是加载不同的运行时CLR部件和优化在域的整个生命期内存在的部件。这些堆的增长基于可预测块,这样可以使碎片最小化。加载器堆不同于垃圾回收堆(或者对称多处理器上的多个堆),垃圾回收堆保存对象实例,而加载器堆同时保存类型系统。经常访问的部件如方法表,方法描述,域描述和接口图,分配在高频堆上,而较少访问的数据结构如EEClass和类加载器及其查找表,分配在低频堆。代理堆保存用于代码访问安全性(code access security, CAS)的代理部件,如COM封装调用和平台调用(P/Invoke)。
从高层次了解域后,我们准备看看它们在一个简单的应用程序的上下文中的物理细节,见 图3。我们在程序运行时停在mc.Method1(),然后使用SOS调试器扩展命令DumpDomain来输出域的信息。(请查看 Son of Strike了解SOS的加载信息)。这里是编辑后的输出:
图3 Sample1.exe
!DumpDomain System Domain: 793e9d58, LowFrequencyHeap: 793e9dbc, HighFrequencyHeap: 793e9e14, StubHeap: 793e9e6c, Assembly: 0015aa68 [mscorlib], ClassLoader: 0015ab40 Shared Domain: 793eb278, LowFrequencyHeap: 793eb2dc, HighFrequencyHeap: 793eb334, StubHeap: 793eb38c, Assembly: 0015aa68 [mscorlib], ClassLoader: 0015ab40 Domain 1: 149100, LowFrequencyHeap: 00149164, HighFrequencyHeap: 001491bc, StubHeap: 00149214, Name: Sample1.exe, Assembly: 00164938 [Sample1], ClassLoader: 00164a78
using System;public interface MyInterface1 {void Method1();void Method2(); }public interface MyInterface2 {void Method2();void Method3(); }class MyClass : MyInterface1, MyInterface2 {public static string str = "MyString";public static uint ui = 0xAAAAAAAA;public void Method1() { Console.WriteLine("Method1"); }public void Method2() { Console.WriteLine("Method2"); }public virtual void Method3() { Console.WriteLine("Method3"); } }class Program {static void Main() { MyClass mc = new MyClass(); MyInterface1 mi1 = mc; MyInterface2 mi2 = mc;int i = MyClass.str.Length;uint j = MyClass.ui; mc.Method1(); mi1.Method1(); mi1.Method2(); mi2.Method2(); mi2.Method3(); mc.Method3(); } }
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流