天天躁日日躁狠狠躁AV麻豆-天天躁人人躁人人躁狂躁-天天澡夜夜澡人人澡-天天影视香色欲综合网-国产成人女人在线视频观看-国产成人女人视频在线观看

.NET Discovery 系列之六--Me JIT(下)

系列文章導航:

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

.NET Discovery 系列之二--string從入門到精通(勘誤版下)

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

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

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

.NET Discovery 系列之六--Me JIT(下)

.NET Discovery 系列之七--深入理解.NET垃圾收集機制(拾貝篇)


  接上文

  在初始化時,HashTable中各個方法指向的并不是對應的內存入口地址,而是一個JIT預編譯代理,這個函數負責將方法編譯為本地代碼。注意,這里JIT還沒有進行編譯,只是建立了方法表

  下表(表1)為首次加載調用時HashTable的情況:

  表1 方法表示意

方法槽

方法描述

a1()

PreJitStub

a2()

PreJitStub

a3()

PreJitStub

  好了有了這個HashTable后,JIT開始編譯第一個被調用的方法A.a1("First"),這是由一個JIT內部函數來完成的(上面提到的),遺憾的事,目前還沒有發現介紹這個函數的相關資料,有些書中稱它為“JIT編譯者”,那本文也這么稱呼它吧。

  下圖為首次調用方法時的示意圖:

圖2 觸發JIT編譯

  JIT借助元數據和IL生成被調用方法的本地代碼后,會將這些代碼緩存在動態內存中,然后修改HashTable中對應方法的入口地址,將其修改為本地代碼的內存片地址(如表2所示),并將這個地址返回給CLR經行執行,A.a1("First")執行完畢,代碼繼續運行。

運行至A.a1("Second ")時,會直接執行A.a1()方法的內存代碼,不會進行再次編譯,表2 為再次加載時HashTable的情況。

表2 方法表變化

方法槽

方法描述

a1()

XXXXXXXXX內存地址

a2()

PreJitStub

a3()

PreJitStub

再次加載流程示意圖:

圖3 未觸發JIT編譯

圖4 方法表、方法描述、預編譯代理關系

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

  1. 查找程序集中包含的對應類型清單,并調用元數據遍歷出包含的方法。
  2. 結合元數據獲得這個方法的IL。
  3. 分配內存。
  4. 編譯IL為本地代碼,并保存在第3步所分配的內存中。
  5. 將類型表(就是指上文中提到的HashTable)中方法地址修改為第3步所分配的內存地址。
  6. 跳轉至本地代碼中執行。

  所以隨著程序的運行時間增加,越來越多的方法的IL被編譯為本地代碼,JIT的調用次數也會不斷減少。

  下面借助WinDbg來證實以上的說法,示例中的源程序可以到這里下載到:

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

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

  好,第一步運行JITTester.exe程序,并打開WinDbg附加這個進程

圖 5 附件進程

  第二步,附加進程成功后,在WinDbg中加載SOS.dll

圖6 加載SOS.dll

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

圖7 查看類型信息

  回車后注意高亮區域的信息:

圖8 JIT前A類型的信息

  高亮區域顯示的是“”,這說明雖然運行和程序,但未點擊按鈕時,A類型未被JIT,因為它還沒有入口地址。這一點體現了即時、按需編譯的思想。

  同樣,!name2ee *!JITTester.B和!name2ee *!JITTester.C命令會得到同樣的結果。

  好,現在做第4步操作,Detach Debuggee進程,并回到程序中點擊“GO”按鈕

圖9 點擊按鈕

  第五步 重新附加進程(參考第一步),這時程序已經調用了new A().a1()方法,并重新執行命令!name2ee *!JITTester.A ,注意高亮部分

圖10 JIT后A類型的信息

  和圖8中的信息比較,圖10中的方法表地址已經變為JIT后的內存地址,這時圖4中的Stub槽將被一條強制跳轉語句替換,跳轉目標與該地址有關。這一點說明JIT在大多情況下,只編譯一次代碼。

  同樣命令查看B類型:

圖11 JIT后B類型的信息

  該類型未被調用,所以還未被JIT。

  C類型:

圖12 JIT后C類型的信息    

  由于實例化A類型時和C類型相關,所以C類型已經JIT了。

  第三節.Native Image Generator

  Native Image Generator中文譯為本地代碼生成器,我更習慣叫它“本地映像”,因為通過工具NGen.exe生成的本地代碼是無法部分載入的,這意味著操作系統會加載整個程序集文件。

    上一節中提到過,有兩種方法可以獲得本地代碼,JIT方式和Native Image Generator方式,JIT方式是在運行時動態編譯需要的代碼,而NGen.exe會創建托管程序集的本機映像,并且將該映像安裝到GAC中,運行該程序集時,就會自動使用該本機映像而不是JIT它們。

  這聽起來似乎很美妙,但是你必須做好以下準備:

  1. 當FrameWork版本、CPU類型、操作系統版本發生變化時,.NET會恢復JIT機制。
  2. NGen.exe工具并不能避免發布IL,事實上,即使使用NGen.exe工具,CLR依然會使用到元數據和IL。 
  3. 忽略了局部性原理(上一節中提到的),系統會加載整個映像文件到內存中,并很可能重定位文件,修正內存地址引用。 
  4. NGen.exe生成的代碼無法在運行時進行優化,無法直接訪問靜態資源,也無法在應用程序域之間共享程序集。 

  此外,JIT不但有編譯的本事,還會根據內存資源情況換出使用率低的代碼,節省資源,這對于一些基于.NET平臺的電子產品是很重要的。

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

NET技術.NET Discovery 系列之六--Me JIT(下),轉載需保留來源!

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

主站蜘蛛池模板: 天天操人人射 | 被爽到叫呻呤视频免费视频 | 97国产在线播放 | 亚洲欧美日韩另类精品一区二区三区 | 中国大陆一级毛片免费 | 久久成人精品免费播放 | 免费女人光着全身网站 | 亚洲国产在线精品国自产拍五月 | 91热久久免费频精品动漫99 | 99久久久无码国产精品AAA | 76人遣返航班上71人呈阳性 | 蜜臀AV人妻久久无码精品麻豆 | 无码日韩人妻精品久久蜜桃免费 | 蜜臀亚洲AV永久无码精品老司机 | 韩国女人高潮嗷嗷叫视频 | 午夜国产免费视频亚洲 | 婷婷精品国产亚洲AV在线观看 | 一个人高清在线观看日本免费 | 日韩国产精品欧美一区二区 | 亚洲一二三产品区别在哪里 | 久久精视频 | 狠狠色色综合网站 | 久久亚洲免费视频 | 美女18毛片免费视频 | 亚洲日韩乱码人人爽人人澡人 | 亚洲一卡二卡三卡四卡无卡麻豆 | 偷柏自拍亚洲综合在线 | 9LPORM原创自拍达人 | 色姐妹久久综合在线av | 国产乱色伦影片在线观看 | 亚洲AV无码一区二区三区牛牛 | 日韩hd高清xxxⅹ | 亚洲欧洲免费三级网站 | 手机毛片在线观看 | 两个人的视频hd全免费 | 国产AV午夜精品一区二区入口 | 无限好资源免费观看 | 99久久国产露脸精品麻豆 | 欧洲美女高清一级毛片 | 中文乱码35页在线观看 | 国产日韩在线欧美视频 |