GAC(Global Assembly Cache) 全局程序集緩存緩存
安裝公共語言運行庫的每臺計算機都有一個稱爲全局程序集緩存的機器級代碼緩存。全局程序集緩存存儲專門指定由計算機上的多個應用程序共享的程序集。數據結構
「運行時」如何解析類型引用架構
首先是一組毫無養分可是有用的代碼:ide
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Reflection; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Project_1 9 { 10 public class Program 11 { 12 public static void Main(string[] args) 13 { 14 System.Console.WriteLine("HaHa"); 15 } 16 } 17 }
編譯這些代碼並生成程序集Program.exe。運行應用程序,CLR會加載並初始化自身,讀取程序集的CLR頭,查找標識了應用程序的入口方法main的MethodDefToken,檢索MethodDef元數據表找到方法的IL代碼在文件中的偏移量,將IL代碼Jit編譯成本機代碼,最後執行本機代碼。ui
.method public hidebysig static void Main(string[] args) cil managed // SIG: 00 01 01 1D 0E { .entrypoint // 方法在 RVA 0x2050 處開始 // 代碼大小 13 (0xd) .maxstack 8 IL_0000: /* 00 | */ nop IL_0001: /* 72 | (70)000001 */ ldstr "HaHa" IL_0006: /* 28 | (0A)000003 */ call void [mscorlib]System.Console::WriteLine(string) IL_000b: /* 00 | */ nop IL_000c: /* 2A | */ ret } // end of method Program::Main
對這些代碼進行JIT編譯,CLR會檢測全部類型和成員引用,加載他們的定義程序集。上述IL代碼包含讀System.Console.WriteLine的引用。具體地說,IL call指令引用了元數據token0A000003。該token標識MemberRef元數據表中的記錄項3。CLR檢查該MemberRef記錄項,發現他的字段引用了TypeRef表中的記錄項。按照TypeRef記錄項,CLR被引到至一個AssemblyRef記錄項:spa
AssemblyRef #1 (23000001) ------------------------------------------------------- Token: 0x23000001 Public Key or Token: b7 7a 5c 56 19 34 e0 89 Name: mscorlib Version: 4.0.0.0 Major Version: 0x00000004 Minor Version: 0x00000000 Build Number: 0x00000000 Revision Number: 0x00000000 Locale: <null> HashValue Blob: Flags: [none] (00000000)
這時CLR就知道了他須要的是哪一個程序集。接下來,CLR必須定位該程序集。code
解析引用的類型時,CLR可能在如下三個地方找到類型:blog
●相同文件:編譯時便能發現對相同文件中的類型的訪問,這稱爲早起綁定。類型直接從文件中加載,執行繼續;token
●不一樣文件,相同程序集:「運行時」確保被引用的文件在當前程序集元數據的FileDef表中,檢查假造程序集清單文件的目錄,加載被引用的文件。檢查哈希值以確保文件完整性。發現類型的成員,執行繼續;進程
●不一樣文件,不一樣程序集:若是引用的類型在其餘程序集文件中,「運行時」會加載被引用程序集的清單文件。若是須要的類型不在該文件中,就繼續加載包含了類型的文件。發現該類型的成員,執行繼續。
解析類型引用時有任何錯誤都會拋出異常。
在上例中,CLR發現System.Console在和調用者不一樣的程序集中實現。因此,CLR必須查找到那個程序集,加載包含應用程序集的PE文件。而後掃描清單,判斷是哪一個PE文件實現了類型。若是被引用的類型就在清單文件中,一切都很簡單。若是類型在程序集的另外一個數據結構來表示類型,JIT編譯器完成Main方法的編譯。最後,Main方法開始執行。綁定過程以下圖所示:
還要注意的是,對於CLR,全部程序集都根據名稱、版本、語言文化和公鑰來識別。但GAC根據名稱、版本、語言文化、公鑰和CPU架構來識別。在GAC中搜索程序集時,CLR判斷應用程序當前在什麼類型的進程中運行,是32位x64,64位x64,仍是32位ARM。而後,在GAC中搜索程序集時,CLR首先搜索程序集的CPU架構專用版本。若是沒有找到符合要求的,就搜索不區分CPU的版本。