一、窺探准備工作
public class Base { public void M() { Console.WriteLine("M in Base"); } public virtual void N() { Console.WriteLine("N in Base"); } } public class Three : Base { private static int ID { get; set; } public override void N() { // Something new in class Three Console.WriteLine("N in Three"); } public void M() { Console.WriteLine("M in Three"); M1(); } public void M1() { Console.WriteLine("M1 in Three"); } } public class Program { public static void Main(string[] args) { Base three = new Three(); three.M(); three.N(); Console.ReadKey(); } }
調試運行,執行結果如下圖所示:
二、窺探方法表執行過程
2.1 方法表的創建
執行Main方法調用時,Three實例的創建與相應類型的加載也隨之發生。然而,類型加載是在實例創建之前完成的,也就是我們常常說到的方法表創建。當程序執行到three.N()處時,Three類型的方法表如下圖所示:
2.2 總體執行過程
(1)class loader 從元數據表加載相關元數據信息,根據信息創建方法表(這里主要是指CORINFO_CLASS_STRUCT結構)
(2)加載后,方法表槽都保存了應該執行的行為邏輯,這些信息保存在方法描述(Method Desc)結構中,MethodDesc被初始化為指向IL代碼,同時還包含一個指向觸發JIT編譯的PreJitStub地址
2.3 具體執行過程
這里以N()方法來看看其具體的執行過程:
(1)任何方法第一次執行時都會首先觸發執行JIT編譯,JIT編譯的主要工作就是將IL代碼翻譯為本地代碼,並插入指向本地代碼的jmp指令地址覆蓋原來的Call JIT Complier指令
(2)當該方法再次被執行,因為方法描述(MethodDesc結構)中保存了機器碼地址,以后的執行將不會執行JIT編譯過程而直接執行機器碼,實現整個執行過程。
三、小結
Metadata描述了靜態的結構,而IL闡述了動態的執行,一靜一動承載着很多的技術奧秘。