日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

[你必须知道的.NET]第二十六回:认识元数据和IL(下)

發(fā)布時(shí)間:2023/12/10 asp.net 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [你必须知道的.NET]第二十六回:认识元数据和IL(下) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
說在,開篇之前
書接上回:?
第二十四回:認(rèn)識元數(shù)據(jù)和IL(上),?第二十五回:認(rèn)識元數(shù)據(jù)和IL(中)?

我們繼續(xù)。?

終于到了,說說元數(shù)據(jù)和IL在JIT編譯時(shí)的角色了,雖然兩個(gè)回合的鋪墊未免鋪張,但是卻絲毫不為過,因?yàn)橹挥谐浞值恼J(rèn)知才有足夠的體會(huì),技術(shù)也是如此。那么,我們就開始沿著方法調(diào)用的軌跡,追隨元數(shù)據(jù)和IL在那個(gè)神秘瞬間所貢獻(xiàn)的力量吧。??

??????????????????????????????????????????????????????????????????????????????????????www.anytao.com

?

?

5 元數(shù)據(jù)和IL在JIT編譯時(shí)

CLR最終執(zhí)行的只有本地機(jī)器碼,所以JIT編譯的作用是在運(yùn)行時(shí)將IL代碼解析為機(jī)器碼執(zhí)行。對于JIT編譯,我們會(huì)以專門的篇幅來全面了解,本文只將目光關(guān)注于元數(shù)據(jù)和IL在程序執(zhí)行時(shí)的作用和參與細(xì)節(jié)。首先,IL是基于棧執(zhí)行的,執(zhí)行方法調(diào)用時(shí),方法參數(shù)、局部變量還有返回值等被分配于棧上,并執(zhí)行其調(diào)用過程,既然是關(guān)注JIT編譯時(shí),因此我們自然而然將關(guān)注方法的執(zhí)行,因?yàn)镴IT編譯是以執(zhí)行方法調(diào)用而觸發(fā)的。

首先,對本文開始的代碼加點(diǎn)新料:

// Release : code04, 2009/02/24 // Author : Anytao, http://www.anytao.com // List : Base.cs public class Base {public void M(){Console.WriteLine("M in Base");}public virtual void N(){Console.WriteLine("N in Base");} }

還有:

// Release : code05, 2009/02/24 // Author : Anytao, http://www.anytao.com // List : Three.cs public class Three : Base {private static int ID { get; set; }public override void N(){//Something new in ThreeConsole.WriteLine("N in Three");}public void M(){Console.WriteLine("M in Three");M1();}public void M1(){Console.WriteLine("M1 in Three");} }

還有執(zhí)行代碼:

static void Main(string[] args) {Base three = new Three();three.M();three.N(); }

小窺方法表

以該例而言,執(zhí)行Main方法調(diào)用時(shí),同時(shí)伴隨著對于Three實(shí)例的創(chuàng)建,和相應(yīng)類型信息的加載。我們先將類型信息創(chuàng)建的秘密放在以后的內(nèi)容中,好留點(diǎn)懸念在未來發(fā)揮,哈哈。然而,類型加載一定是在實(shí)例創(chuàng)建之前完成的,也就是我們常常提起的方法表創(chuàng)建。類型加載是由class loader負(fù)責(zé)執(zhí)行的,其過程簡言之就是從元數(shù)據(jù)表中獲取相應(yīng)的類型信息,創(chuàng)建方法表(包含CORINFO_CLASS_STRUCT結(jié)構(gòu)),其結(jié)構(gòu)主要包括非虛方法表和虛方法表,按照繼承的虛方法、新引入的虛方法、實(shí)例方法和靜態(tài)方法的順序排列,以類Three類型為例其CORINFO_CLASS_STRUCT結(jié)構(gòu)可以表示為:

Note: 在本例中Three沒有定義任何靜態(tài)方法,其方法表中父類方法N已有子類覆寫,同時(shí)因?yàn)橛徐o態(tài)成員存在的原因,CLR會(huì)自動(dòng)創(chuàng)建類型構(gòu)造器,詳細(xì)情況可參考《你必須知道的.NET》1.2節(jié) “什么是繼承”。

我們可以同過加載SOS調(diào)試來了解相應(yīng)的方法表信息:

  • 在three.N()調(diào)用處打好斷點(diǎn),來查看該時(shí)刻的dump信息,就像一個(gè)內(nèi)存快照,發(fā)現(xiàn)多少東西就看攝影師的水準(zhǔn)。
  • 然后,通過dumpheap加載類型信息,獲取方法表地址(0x002a354c),
!dumpheap -type Three Address MT Size 01d332c4 002a354c 12 total 1 objects Statistics:MT Count TotalSize Class Name 002a354c 1 12 Anytao.Insidenet.MetadataIL.Three
  • 并根據(jù)MT地址,以dumpmt查看相關(guān)的MethodDesc信息,
!dumpmt -md 002a354c EEClass: 002a15b4 Module: 002a2f2c Name: Anytao.Insidenet.MetadataIL.Three mdToken: 02000003 (E:\anytao\Today\OnWriting\MetadataIL\Anytao.Insidenet.MetadataIL\Anytao.Insidenet.MetadataIL\bin\Debug\Anytao.Insidenet.MetadataIL.exe) BaseSize: 0xc ComponentSize: 0x0 Number of IFaces in IFaceMap: 0 Slots in VTable: 10 -------------------------------------- MethodDesc TableEntry MethodDesc JIT Name 6f756a70 6f5d1328 PreJIT System.Object.ToString() 6f756a90 6f5d1330 PreJIT System.Object.Equals(System.Object) 6f756b00 6f5d1360 PreJIT System.Object.GetHashCode() 6f7c7460 6f5d1384 PreJIT System.Object.Finalize() 002ac0b8 002a3514 NONE Anytao.Insidenet.MetadataIL.Three.N() 002ac0d0 002a3540 JIT Anytao.Insidenet.MetadataIL.Three..ctor() 002ac0a8 002a34f4 NONE Anytao.Insidenet.MetadataIL.Three.get_ID() 002ac0b0 002a3504 NONE Anytao.Insidenet.MetadataIL.Three.set_ID(Int32) 002ac0c0 002a3520 NONE Anytao.Insidenet.MetadataIL.Three.M() 002ac0c8 002a3530 NONE Anytao.Insidenet.MetadataIL.Three.M1()

經(jīng)過簡單的Dump,方法表的信息和我們圖示的信息相差無幾,細(xì)心的觀眾可能會(huì)發(fā)現(xiàn)Dump信息中并不包含Three::cctor(),那么你答對了。圖示的cctor是我基于為Three實(shí)現(xiàn)了類型構(gòu)造器(靜態(tài)構(gòu)造函數(shù))而特別加入的,而代碼中dump的方法表并沒有把類型構(gòu)造器包含在內(nèi),這是個(gè)小粗心,希望細(xì)心的您看得夠透。

執(zhí)行細(xì)則

具體的執(zhí)行過程為為:

  • class loader從TypeDef元數(shù)據(jù)表加載相關(guān)元數(shù)據(jù)信息,包括當(dāng)前類型,繼承層次的所有父類和實(shí)現(xiàn)的接口元數(shù)據(jù),根據(jù)這些信息建立CORINFO_CLASS_STRUCT結(jié)構(gòu):

當(dāng)然,對class loader,我們可以進(jìn)行一點(diǎn)知識救急:

?

上課啦:class loader

Classic Loader是CLR提供的基本組件之一,作用正像其名稱所宣揚(yáng)的那樣,load一個(gè)Class給CLR,class loader將Metadata和IL從PE文件中取出,并加載到運(yùn)行時(shí)內(nèi)存,簡單的說就是我們下面要介紹的全過程縮影。

當(dāng)然,如果你總是對CLR的Classic Loader耿耿于懷,不能釋然。那么,我們也可以參考MSDN的資料來實(shí)現(xiàn)自定義的Classic Loader[How to: Write a Class Loader],希望其中能提供靈光一現(xiàn)的思考。

??????????????????????????????????????????????????????????????????????????????????????www.anytao.com

?

  • 加載之后,方法執(zhí)行之前的CORINFO_CLASS_STRUCT中所有的方法表槽都保存了方法應(yīng)該執(zhí)行的行為邏輯,這些信息保存在被稱為方法描述(MethodsDesc)的結(jié)構(gòu)中,而MethodDesc則被初始化為指向IL代碼,同時(shí)還包含一個(gè)指向觸發(fā)JIT編譯的PreJitStub地址,如下:

上述所有方法描述都指向各自的IL代碼地址和JIT編譯器,在此我們僅僅以N()方法為例來進(jìn)行說明,詳細(xì)的情況可以參考MSDN相關(guān)內(nèi)容。

  • 簡單的說,任何方法第一次執(zhí)行時(shí)都會(huì)首先觸發(fā)執(zhí)行JIT編譯,JIT的主要工作就是將IL代碼翻譯為Native Code,并插入指向Native Code的jmp指令地址覆蓋原來的Call JIT Compiler指令:

  • 當(dāng)該方法再次被執(zhí)行時(shí),因?yàn)镸ethodDesc中保存了機(jī)器碼地址,以后的執(zhí)行將不會(huì)執(zhí)行JIT編譯過程而直接執(zhí)行x86(X64)機(jī)器碼,實(shí)現(xiàn)整個(gè)執(zhí)行過程。

縱觀整個(gè)JIT編譯的全過程,其細(xì)節(jié)的實(shí)現(xiàn)遠(yuǎn)比我們這里呈現(xiàn)的復(fù)雜,在粗略的步驟中我們大致了解了元數(shù)據(jù)和IL在整個(gè)過程中的作用、角色和關(guān)系,對了解CLR運(yùn)行機(jī)制而言,適當(dāng)?shù)倪x擇是明智的,如果有更多的心思探索,那么就在以后的歲月中由簡及繁吧,但是相信這一定是一次美妙的旅程。

6 結(jié)論

Metadata描述了靜態(tài)的結(jié)構(gòu),而IL闡釋了動(dòng)態(tài)的執(zhí)行,這一靜一動(dòng)承載了太多的技術(shù)奧秘。

當(dāng)這篇文章行將結(jié)束的時(shí)候,我發(fā)現(xiàn)牽一發(fā)而動(dòng)全身,由此引入的新問題接踵而至,方法調(diào)用、程序集、程序域、CLR加載過程在元數(shù)據(jù)和IL的分析中若隱若現(xiàn),也驅(qū)使我投入注意在后面的《你必須知道的.NET》中,將這些內(nèi)容一一過招。由此才能在復(fù)雜的概念和本質(zhì)之余,由點(diǎn)及面的對所有內(nèi)容綜合把握,形成全面的了解和一條線貫穿的認(rèn)識,那么未來Anytao將要繼續(xù)分享還有:

系列預(yù)告
  • 程序集和模塊
  • 程序域
  • CLR加載過程
  • JIT編譯
  • 方法調(diào)用
  • 反射種種
  • 其他…

??????????????????????????????????????????????????????????????????????????????????????www.anytao.com

限于繁忙的原因,我無法給出一個(gè)清晰的時(shí)間表,但力圖每次的內(nèi)容都給您出足夠的收獲,如果你對.NET始終心懷興致,那么敬請期待《你必須知道的.NET》更多精彩。?


支持anytao的創(chuàng)業(yè)產(chǎn)品Worktile
Worktile,新一代簡單好用、體驗(yàn)極致的團(tuán)隊(duì)協(xié)同、項(xiàng)目管理工具,讓你和你的團(tuán)隊(duì)隨時(shí)隨地一起工作。完全免費(fèi),現(xiàn)在就去了解一下吧。
https://worktile.com

  • 《你必須知道的.NET》第3章 “一切從IL開始”
  • DonBox,《.NET本質(zhì)論》
  • http://www.sloppycode.net/articles/inside-net-assemblies-and-metadata.aspx
  • http://www.codeproject.com/KB/dotnet/dotnetformat.aspx

溫故知新

總結(jié)

以上是生活随笔為你收集整理的[你必须知道的.NET]第二十六回:认识元数据和IL(下)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。