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

歡迎訪問(wèn) 生活随笔!

生活随笔

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

asp.net

.Net Discovery 系列之六--深入浅出.Net实时编译机制(下)

發(fā)布時(shí)間:2025/6/15 asp.net 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 .Net Discovery 系列之六--深入浅出.Net实时编译机制(下) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

????接上文

??? 在初始化時(shí),HashTable中各個(gè)方法指向的并不是對(duì)應(yīng)的內(nèi)存入口地址,而是一個(gè)JIT預(yù)編譯代理,這個(gè)函數(shù)負(fù)責(zé)將方法編譯為本地代碼。注意,這里JIT還沒(méi)有進(jìn)行編譯,只是建立了方法表!

??? 下表(表1)為首次加載調(diào)用時(shí)HashTable的情況:

?????????????????????表1 方法表示意

方法槽

方法描述

a1()

PreJitStub

a2()

PreJitStub

a3()

PreJitStub

??? 好了有了這個(gè)HashTable后,JIT開(kāi)始編譯第一個(gè)被調(diào)用的方法A.a1("First"),這是由一個(gè)JIT內(nèi)部函數(shù)來(lái)完成的(上面提到的),遺憾的事,目前還沒(méi)有發(fā)現(xiàn)介紹這個(gè)函數(shù)的相關(guān)資料,有些書(shū)中稱它為“JIT編譯者”,那本文也這么稱呼它吧。

??? 下圖為首次調(diào)用方法時(shí)的示意圖:

?

?

圖2 觸發(fā)JIT編譯

??? JIT借助元數(shù)據(jù)和IL生成被調(diào)用方法的本地代碼后,會(huì)將這些代碼緩存在動(dòng)態(tài)內(nèi)存中,然后修改HashTable中對(duì)應(yīng)方法的入口地址,將其修改為本地代碼的內(nèi)存片地址(如表2所示),并將這個(gè)地址返回給CLR經(jīng)行執(zhí)行,A.a1("First")執(zhí)行完畢,代碼繼續(xù)運(yùn)行。

??? 運(yùn)行至A.a1("Second ")時(shí),會(huì)直接執(zhí)行A.a1()方法的內(nèi)存代碼,不會(huì)進(jìn)行再次編譯,表2 為再次加載時(shí)HashTable的情況。

????????????? 表2 方法表變化

方法槽

方法描述

a1()

XXXXXXXXX內(nèi)存地址

a2()

PreJitStub

a3()

PreJitStub

??? 再次加載流程示意圖:

?

圖3 未觸發(fā)JIT編譯

?

?

圖4 方法表、方法描述、預(yù)編譯代理關(guān)系

?

??? 圖2中所示的MS核心引擎指的是一個(gè)叫做MSCorEE的DLL,即Microsoft .NET Runtime Execution Engine,它是一個(gè)橋接DLL,連同mscorwks.dll主要完成以下工作:

  • 查找程序集中包含的對(duì)應(yīng)類型清單,并調(diào)用元數(shù)據(jù)遍歷出包含的方法。
  • 結(jié)合元數(shù)據(jù)獲得這個(gè)方法的IL。
  • 分配內(nèi)存。
  • 編譯IL為本地代碼,并保存在第3步所分配的內(nèi)存中。
  • 將類型表(就是指上文中提到的HashTable)中方法地址修改為第3步所分配的內(nèi)存地址。
  • 跳轉(zhuǎn)至本地代碼中執(zhí)行。
  • ??? 所以隨著程序的運(yùn)行時(shí)間增加,越來(lái)越多的方法的IL被編譯為本地代碼,JIT的調(diào)用次數(shù)也會(huì)不斷減少。

    ????? 下面借助WinDbg來(lái)證實(shí)以上的說(shuō)法,示例中的源程序可以到這里下載到:

    ????? http://files.cnblogs.com/isline/IsLine.JITTester.rar

    ?

    namespace JITTester

    {

    public partial class
    Form1 : Form

    {

    public
    Form1()

    {

    InitializeComponent();

    }



    private void Form1_Load(object
    sender, EventArgs e)

    {



    }



    private void GO_Click(object
    sender, EventArgs e)

    {

    new
    A().a1();

    lb_msg.Text
    = "調(diào)用完畢!"
    ;



    }

    }



    class
    A

    {

    public void
    a1() { }

    public C a2 = new
    C();

    }



    class
    B

    {

    public void
    b1() { }

    public void
    b2() { }

    }



    class
    C

    {

    public void
    c1() { }

    public void
    c2() { }

    }

    }

    ?

    ????? 代碼中定義了3個(gè)類,分別為A、B、C,在“GO”按鈕按下后,將調(diào)用類型A中的a1()方法,而Form1_Load 中什么也不做,目的是程序運(yùn)行后,在空載的情況下查看方法描述對(duì)應(yīng)地址入口的情況。

    ??? 好,第一步運(yùn)行JITTester.exe程序,并打開(kāi)WinDbg附加這個(gè)進(jìn)程

    ?

    圖 5 附件進(jìn)程

    ?

    ?? 第二步,附加進(jìn)程成功后,在WinDbg中加載SOS.dll

    ?

    圖6 加載SOS.dll

    ??? 第三步,使用name2ee命令遍歷所有已加載模塊,name2ee格式為name2ee *! [程序集].[類型]

    ?

    圖7 查看類型信息

    ??? 回車后注意高亮區(qū)域的信息:

    ?

    圖8 JIT前A類型的信息

    ??? 高亮區(qū)域顯示的是“<not loaded yet>”,這說(shuō)明雖然運(yùn)行和程序,但未點(diǎn)擊按鈕時(shí),A類型未被JIT,因?yàn)樗€沒(méi)有入口地址。這一點(diǎn)體現(xiàn)了即時(shí)、按需編譯的思想。

    ?? 同樣,!name2ee *!JITTester.B和!name2ee *!JITTester.C命令會(huì)得到同樣的結(jié)果。

    ??? 好,現(xiàn)在做第4步操作,Detach Debuggee進(jìn)程,并回到程序中點(diǎn)擊“GO”按鈕

    ?

    ?

    圖9 點(diǎn)擊按鈕

    ?

    ??? 第五步 重新附加進(jìn)程(參考第一步),這時(shí)程序已經(jīng)調(diào)用了new A().a1()方法,并重新執(zhí)行命令!name2ee *!JITTester.A ,注意高亮部分

    ?

    圖10 JIT后A類型的信息

    ??? 和圖8中的信息比較,圖10中的方法表地址已經(jīng)變?yōu)镴IT后的內(nèi)存地址,這時(shí)圖4中的Stub槽將被一條強(qiáng)制跳轉(zhuǎn)語(yǔ)句替換,跳轉(zhuǎn)目標(biāo)與該地址有關(guān)。這一點(diǎn)說(shuō)明JIT在大多情況下,只編譯一次代碼。

    ??? 同樣命令查看B類型:

    ?

    圖11 JIT后B類型的信息

    ??? 該類型未被調(diào)用,所以還未被JIT。

    ??? C類型:

    ?

    圖12 JIT后C類型的信息

    ?

    ??? 由于實(shí)例化A類型時(shí)和C類型相關(guān),所以C類型已經(jīng)JIT了。

    ??? 第三節(jié).Native Image Generator

    ??? Native Image Generator中文譯為本地代碼生成器,我更習(xí)慣叫它“本地映像”,因?yàn)橥ㄟ^(guò)工具NGen.exe生成的本地代碼是無(wú)法部分載入的,這意味著操作系統(tǒng)會(huì)加載整個(gè)程序集文件。

    ??? 上一節(jié)中提到過(guò),有兩種方法可以獲得本地代碼,JIT方式和Native Image Generator方式,JIT方式是在運(yùn)行時(shí)動(dòng)態(tài)編譯需要的代碼,而NGen.exe會(huì)創(chuàng)建托管程序集的本機(jī)映像,并且將該映像安裝到GAC中,運(yùn)行該程序集時(shí),就會(huì)自動(dòng)使用該本機(jī)映像而不是JIT它們。

    這聽(tīng)起來(lái)似乎很美妙,但是你必須做好以下準(zhǔn)備:

  • 當(dāng)FrameWork版本、CPU類型、操作系統(tǒng)版本發(fā)生變化時(shí),.Net會(huì)恢復(fù)JIT機(jī)制。
  • NGen.exe工具并不能避免發(fā)布IL,事實(shí)上,即使使用NGen.exe工具,CLR依然會(huì)使用到元數(shù)據(jù)和IL。?
  • 忽略了局部性原理(上一節(jié)中提到的),系統(tǒng)會(huì)加載整個(gè)映像文件到內(nèi)存中,并很可能重定位文件,修正內(nèi)存地址引用。?
  • NGen.exe生成的代碼無(wú)法在運(yùn)行時(shí)進(jìn)行優(yōu)化,無(wú)法直接訪問(wèn)靜態(tài)資源,也無(wú)法在應(yīng)用程序域之間共享程序集。?
  • ??? 此外,JIT不但有編譯的本事,還會(huì)根據(jù)內(nèi)存資源情況換出使用率低的代碼,節(jié)省資源,這對(duì)于一些基于.Net平臺(tái)的電子產(chǎn)品是很重要的。?

    ??? 所以,除非你已十分清楚程序性能是由于首次編譯造成的性能問(wèn)題,否則盡量不要人工生成本地代碼。?

    ?

    ??? 我是李鳴(Aicken) 請(qǐng)您繼續(xù)關(guān)注我的下一篇文章。

    ?

    ????“.Net Discovery 系列”推薦:

    ???? .Net Discovery 系列之五--Me JIT(上)

    ???? .Net Discovery 系列之三--深入理解.Net垃圾收集機(jī)制(上)

    ??? ?.Net Discovery 系列之四--深入理解.Net垃圾收集機(jī)制(下)

    ??? ?.Net Discovery 系列之一--string從入門到精通(上)

    ??? ?.Net Discovery 系列之二--string從入門到精通(下)

    總結(jié)

    以上是生活随笔為你收集整理的.Net Discovery 系列之六--深入浅出.Net实时编译机制(下)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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