1.什麼是CLR算法
CLR(Common Language Runtime)公共語言運行時,是一個可由多種編程語言使用的「運行時」。CLR的核心功能(好比內存管理、程序集加載、安全性、異常處理和線程同步)可由面向CLR的全部語言使用。CLR不關心開發人員使用哪一種語言進行編程,只要編譯器面向CLR就能夠了,全部,開發人員應該使用本身最適合和熟悉的語言進行編程。全部的編程語言在面向CLR編譯器的編譯都生成了一個託管模塊。託管模塊是一個標準的32位的Microsoft Windows可移植執行體(PE32)文件,或者是一個標準的64位Windows可移植的PE32+文件,他們都須要CLR才能執行。編程
2.託管模塊的各個組成部分安全
PE32或PE32+頭 標準Windows PE文件頭,相似於「公共對象文件格式」。數據結構
CLR頭 包含使用這個模塊成爲一個託管模塊的信息(可由CLR和一些實用程序進行解釋)。頭中包含了須要的CLR版本,一些標誌,託管模塊人口方法(Main方法)的MethodDef元數據標記(token),以及模塊的元數據、資源、強名稱、一些flag以及其餘不過重要的數據項的位置/大小編程語言
元數據 每一個託管模塊都包含元數據表。主要有兩種類型的表:一種類型的表描述源代碼中定義的類型和成員:另外一種類型的表描述源代碼引用類型和成員ide
IL(中間語言)代碼 編譯器編譯源代碼時生成的代碼。在運行時,CLR將將IL編譯成本地的CPU指令函數
元數據的用途:ui
編譯時,元數據消除了對本地C/C++頭和庫文件的需求,由於在負責實現類型/成員的IL代碼中,已包和引用的類型/成員有關的所有信息。編譯器可直接從託管模塊讀取元數據線程
Microsoft Visual Studio 使用元數據幫助你寫代碼。也就是「智能感知(IntelliSense)技術」能夠解析元數據,指出一個類型提供了那些方法、屬性、事件和字段等等。版本控制
CLR的代碼驗證過程使用元數據確保代碼只執行「類型安全」的操做。
元數據容許將一個對象的字段序列化到一個內存中,將其發送給另外一臺機器,而後反序列化,在遠程機器上重建對象的狀態
元數據容許垃圾回收器跟蹤對象的生存期。垃圾回收器能判斷任何對象的類型,並從元數據知道那個對象中的哪些字段引用了其餘對象。
3.程序集
其實,CLR不和託管模塊一塊兒工做。它和程序集(assembly)一塊工做。程序集是一個或多個模塊/資源文件的邏輯分組。程序集是重用、安全性已經版本控制的最小單元。程序集是自描述的(self-describing)
4 執行程序集的代碼
託管程序集同時包含元數據和IL。爲了執行程序,首先必須把它的IL轉換成本地CPU指令。這是CLR的JIT(just-in-time)編譯器的職責。
下面我將複述一下一個書的例子來講明一個程序集中的代碼是如何執行的。
在Main方法執行以前,CLR會檢測出Main的代碼引用的全部類型。這將致使CLR分配一個內部數據結構,它用來管理對所用引用的類型的訪問。例如上圖,Main方法引用了一Console類型,這致使CLR分配一個內部結構。在這個內部結構中,Console類型定義的每一個方法都有一個對應的記錄項。每一個記錄項都容納一個地址,根據此地址既能夠找到方法的實現。對這個結構進行初始時,CLR將每一個記錄項都設置成(指向)包含在CLR內部的一個未文檔化的函數。我將這個函數成爲JITCompiler。
Main首次調用WriteLine時,JITCompiler函數會被調用。JITCompiler函數負責將一個方法IL代碼編譯成本地CPU指令。因爲IL是「即時」(just in time)編譯的,因此一般CLR的這個組件稱爲JITter或者JIT編譯器。
JITCompiler函數被調用時,它知道要調用的是哪一個方法,以及具體是什麼類型定義了該方法。而後,JITCompiler會在定義程序集的元數據中查找被調用的方法的IL。接着,JITCompiler驗證IL代碼,並將IL代碼編譯成本地CPU指令。本地CPU指令被保存到一個動態分配的內存塊中。而後,JITCompiler返回CLR爲類型建立的內部數據結構,找到與被調用的方法對象的那一條記錄,修改最初對JITCompiler的引用,讓它如今指向內存塊中的地址。最後,JITCompiler函數跳轉到內存塊中的代碼。
第二次調用WriteLine。這一次,因爲對WriteLine的代碼進行了驗證和編譯,因此直接執行內存塊中的代碼,徹底跳過JITCompiler函數。
第二次調用WriteLine的狀況
5.通用類型系統
爲了經過類型,用一種編程語言寫的代碼能與用另外一種語言寫的代碼溝通,Microsoft指定了一正式的規範,即「通用類型系統」(Common Type System,CTS),它描述了類型的定義和行爲。
CTS規範規定,一個類型能夠包含零個或多個成員。
字段(Field) 一個數據變量
方法(Method) 一個函數
屬性(Property) 對於調用者,該成員看起來像是一個字段
事件(Event) 事件在對象以及其餘相關對象之間實現了一通用機制。
CTS 還指定了類型可視性規則以及類型成員的訪問規則,例如private,family等
CTS還爲類型繼承。虛方法、對象生存期等定義了相應的規則
特比說一下CTS中的一條規則:全部類型最終必須從預約義的System.Object類型繼承。System.Object能夠作的事情以下:
比較兩個實例的相等性
獲取實例的哈希碼
查詢一個實例的真正類型
執行實例的淺拷貝
獲取視實例對象的當前狀態的一個字符串表示
6.公共語言規範
爲了建立很容易從其餘編程語言中訪問的類型,只能從本身的編程語言中挑選其餘全部語言都肯定支持的那些功能,Microsoft定義了一個「公共語言規範」(Common Language Specifiaction,CLS),它詳細定義了一個最小功能集。
7.元數據
上面已經提到託管的PE文件由4個部分構成:PE32(+)頭、CLR頭、元數據以及IL。
這裏咱們主要說一下元數據。
元數據是一個二進制數據塊,由幾個表構成。這些表分爲三個類別:定義表(definiton talbe)、引用表(reference table)和清單表(mainfest table)。
經常使用元數據定義表(編譯器編譯源代碼時,代碼定義的任何同樣東西都會致使定義表中的表中建立一個記錄項):
ModuleDef 老是包含一個用於標示模塊的記錄項。
TypeDef 模塊中定義的每一個類型都在這個定義表中有一個對應的記錄項。
MethodDef 模塊中定義的每一個方法都在這個定義表中有一個對應的記錄項。
FieldDef 模塊中定義的每一個字段都在這個定義表中有一個對應的記錄項
ParamDef 模塊中定義的每一個參數都在這個定義表中有一個對應的記錄項
PropertyDef 模塊中定義的每一個屬性都在這個定義表中有一個對應的記錄項
EventDef 模塊中定義的每一個事件都在這個定義表中有一個對應的記錄項
經常使用的引用元數據表:
AssemblyRef 模塊中引用的每一個程序集在這個表中都有一個對應的記錄項
ModuleRef 模塊引用的每一個類型多是由別的PE模塊實現的,全部那些模塊在這個表都有一個記錄項
TypeDef 模塊引用的每一個類型在這個表中都有一個對應的記錄項
MemberRef 模塊引用的每一個成員都在這個表中有一個對應的記錄項
清單元數據表:
AssemblyDef 若是該模塊標示的是一個程序集,就在這個元數據表中包含單個記錄項。該記錄項列出了程序集名稱(不含路徑和擴展名)、版本(major,minor,build和revision)、語言文化(culture)、一些標誌(flag)、哈希算法以及發佈者的公鑰。
FileDef 做爲程序集一部分的每一個PE文件和資源文件在這個表中都有一個對應的記錄項。
MainifestResourceDef 做爲程序集一部分的每一個資源在這個表中都有一個對應的記錄項
ExportedTypesDef 從程序集的全部PE模塊中導出的每一個public類型中在這個表中都有一個對應的記錄項。