|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
C#中有两处地方用到new关键字,第一处也是最常见的一处是用在调用构造函数的时候,这种情况也是大家见的最多的一种。另一处是用在派生类中,作用有隐藏成员,切断继承关系等,相信第二处的用法大家明显要比第一处生疏。系列文章目次索引:《你必需晓得的.NET》
<br>说在,开篇之前书接上回:
第二十四回:熟悉元数据和IL(上),第二十五回:熟悉元数据和IL(中)
我们持续。
终究到了,说说元数据和IL在JIT编译时的脚色了,固然两个回合的展垫不免浪费,可是却涓滴不为过,由于只要充实的认知才有充足的体味,手艺也是云云。那末,我们就入手下手沿着办法挪用的轨迹,跟随元数据和IL在谁人奥秘刹时所奉献的力气吧。5元数据和IL在JIT编译时
CLR终极实行的只要当地呆板码,以是JIT编译的感化是在运转时将IL代码剖析为呆板码实行。关于JIT编译,我们会以专门的篇幅来周全懂得,本文只将眼光存眷于元数据和IL在程序实行时的感化和介入细节。起首,IL是基于栈实行的,实行办法挪用时,办法参数、部分变量另有前往值等被分派于栈上,并实行其挪用历程,既然是存眷JIT编译时,因而我们天然而然将存眷办法的实行,由于JIT编译是以实行办法挪用而触发的。
起首,对本文入手下手的代码加点新料:- //Release:code04,2009/02/24//Author:Anytao,http://www.anytao.com//List:Base.cspublicclassBase{publicvoidM(){Console.WriteLine("MinBase");}publicvirtualvoidN(){Console.WriteLine("NinBase");}}
复制代码 另有:- //Release:code05,2009/02/24//Author:Anytao,http://www.anytao.com//List:Three.cspublicclassThree:Base{privatestaticintID{get;set;}publicoverridevoidN(){//SomethingnewinThreeConsole.WriteLine("NinThree");}publicvoidM(){Console.WriteLine("MinThree");M1();}publicvoidM1(){Console.WriteLine("M1inThree");}}
复制代码 另有实行代码:- staticvoidMain(string[]args){Basethree=newThree();three.M();three.N();}
复制代码 小窥办法表
以该例而言,实行Main办法挪用时,同时陪伴着关于Three实例的创立,和响应范例信息的加载。我们先将范例信息创立的奥密放在今后的内容中,好留点牵挂在将来发扬,哈哈。但是,范例加载必定是在实例创立之前完成的,也就是我们经常提起的办法表创立。范例加载是由classloader卖力实行的,其历程简言之就是从元数据表中猎取响应的范例信息,创立办法表(包括CORINFO_CLASS_STRUCT布局),其布局次要包含非虚办法表和虚办法表,依照承继的虚办法、新引进的虚办法、实例办法和静态办法的按次分列,以类Three范例为例其CORINFO_CLASS_STRUCT布局能够暗示为:
<br>
Note:在本例中Three没有界说任何静态办法,其办法表中父类办法N已有子类覆写,同时由于有静态成员存在的缘故原由,CLR会主动创立范例机关器,具体情形可参考《你必需晓得的.NET》1.2节“甚么是承继”。
我们能够同过加载SOS调试来懂得响应的办法表信息:
- 在three.N()挪用处打好断点,来检察该时候的dump信息,就像一个内存快照,发明几工具就看拍照师的水准。
- 然后,经由过程dumpheap加载范例信息,猎取办法表地点(0x002a354c),
- !dumpheap-typeThreeAddressMTSize01d332c4002a354c12total1objectsStatistics:MTCountTotalSizeClassName002a354c112Anytao.Insidenet.MetadataIL.Three
复制代码
- 并依据MT地点,以dumpmt检察相干的MethodDesc信息,
- !dumpmt-md002a354cEEClass:002a15b4Module:002a2f2cName:Anytao.Insidenet.MetadataIL.ThreemdToken:02000003(E:anytaoTodayOnWritingMetadataILAnytao.Insidenet.MetadataILAnytao.Insidenet.MetadataILinDebugAnytao.Insidenet.MetadataIL.exe)BaseSize:0xcComponentSize:0x0NumberofIFacesinIFaceMap:0SlotsinVTable:10--------------------------------------MethodDescTableEntryMethodDescJITName6f756a706f5d1328PreJITSystem.Object.ToString()6f756a906f5d1330PreJITSystem.Object.Equals(System.Object)6f756b006f5d1360PreJITSystem.Object.GetHashCode()6f7c74606f5d1384PreJITSystem.Object.Finalize()002ac0b8002a3514NONEAnytao.Insidenet.MetadataIL.Three.N()002ac0d0002a3540JITAnytao.Insidenet.MetadataIL.Three..ctor()002ac0a8002a34f4NONEAnytao.Insidenet.MetadataIL.Three.get_ID()002ac0b0002a3504NONEAnytao.Insidenet.MetadataIL.Three.set_ID(Int32)002ac0c0002a3520NONEAnytao.Insidenet.MetadataIL.Three.M()002ac0c8002a3530NONEAnytao.Insidenet.MetadataIL.Three.M1()
复制代码 经由复杂的Dump,办法表的信息和我们图示的信息相差无几,仔细的不雅众大概会发明Dump信息中其实不包括Three::cctor(),那末你答对了。图示的cctor是我基于为Three完成了范例机关器(静态机关函数)而出格到场的,而代码中dump的办法表并没有把范例机关器包括在内,这是个小大意,但愿仔细的您看得够透。
实行细则
详细的实行历程为为:
- classloader从TypeDef元数据表加载相干元数据信息,包含以后范例,承继条理的一切父类和完成的接口元数据,依据这些信息创建CORINFO_CLASS_STRUCT布局:
<br>
固然,对classloader,我们能够举行一点常识济急:
<br>上课啦:classloaderClassicLoader是CLR供应的基础组件之一,感化正像其称号所宣传的那样,load一个Class给CLR,classloader将Metadata和IL从PE文件中掏出,并加载到运转时内存,复杂的说就是我们上面要先容的全历程缩影。
固然,假如你老是对CLR的ClassicLoader铭心镂骨,不克不及豁然。那末,我们也能够参考MSDN的材料来完成自界说的ClassicLoader[Howto:WriteaClassLoader],但愿个中能供应灵光一现的思索。
anytao.com
- 加载以后,办法实行之前的CORINFO_CLASS_STRUCT中一切的办法表槽都保留了办法应当实行的举动逻辑,这些信息保留在被称为办法形貌(MethodsDesc)的布局中,而MethodDesc则被初始化为指向IL代码,同时还包括一个指向触发JIT编译的PreJitStub地点,以下:
<br>
上述一切办法形貌都指向各自的IL代码地点和JIT编译器,在此我们仅仅以N()办法为例来举行申明,具体的情形能够参考MSDN相干内容。
- 复杂的说,任何办法第一次实行时城市起首触发实行JIT编译,JIT的次要事情就是将IL代码翻译为NativeCode,并拔出指向NativeCode的jmp指令地点掩盖本来的CallJITCompiler指令:
<br>
- 当该办法再次被实行时,由于MethodDesc中保留了呆板码地点,今后的实行将不会实行JIT编译历程而间接实行x86(X64)呆板码,完成全部实行历程。
纵不雅全部JIT编译的全历程,其细节的完成远比我们这里出现的庞大,在大略的步骤中我们大抵懂得了元数据和IL在全部过程当中的感化、脚色和干系,对懂得CLR运转机制而言,得当的选择是明智的,假如有更多的心机探究,那末就在今后的光阴中由简及繁吧,可是信任这必定是一次美好的路程。
6结论
Metadata形貌了静态的布局,而IL阐释了静态的实行,这一静一动承载了太多的手艺奥妙。
当这篇文章即将停止的时分,我发明牵一发而动满身,由此引进的新成绩接二连三,办法挪用、程序集、程序域、CLR加载历程在元数据和IL的剖析中一目了然,也使令我投进注重在前面的《你必需晓得的.NET》中,将这些内容逐一过招。由此才干在庞大的观点和实质之余,由点及面的对一切内容综合掌控,构成周全的懂得和一条线贯串的熟悉,那末将来Anytao将要持续分享另有:
<br>系列预报
- 程序集和模块
- 程序域
- CLR加载历程
- JIT编译
- 办法挪用
- 反射各种
- 其他…
anytao.com
限于忙碌的缘故原由,我没法给出一个明晰的工夫表,但力争每次的内容都给您出充足的劳绩,假如你对.NET一直心胸兴趣,那末敬请等候《你必需晓得的.NET》更多出色。参考文献
- 《你必需晓得的.NET》第3章“统统从IL入手下手”
- DonBox,《.NET实质论》
- http://www.sloppycode.net/articles/inside-net-assemblies-and-metadata.aspx
- http://www.codeproject.com/KB/dotnet/dotnetformat.aspx
来自:http://www.ckuyun.com/anytao/archive/2009/03/04/must_net_26.html
因为二次编译器太复杂,那么建议只是在安装程序的时候编译一次,而不类似net网页编程那样运行就编译。并且我觉得,一次痛苦,总比多次低效率要舒服多了。 |
|