CLR via C#深解筆記一 - CLR & C# 基礎概念

寫在前言
 
.Net Framework並非Win 32 API 和COM上的一個抽象層。
 
某種程度上,它是本身的操做系統,有本身的內存管理器,本身的安全系統,本身的文件加載器,本身的錯誤處理機制,本身的應用程序隔離邊界(AppDomains),本身的線程處理模型等。
隨着多核計算機愈來愈廣泛,線程處理,併發執行,並行結構,同步等方面的重要性日益凸顯。
 
CLR的執行模型
 
公共語言運行時 CLR Common Language Runtime
是一個運行時環境,保證應用和底層操做系統之間必要的分離,是.NET Framework的主要執行引擎。是可由面向CLR的多種編程語言使用的「運行時」。CLR的核心功能(內存管理、程序集加載、安全性、異常處理和線程同步等)由面向CLR的全部語言使用。CLR不關心開發人員使用哪種語言來寫源代碼。也就是說挑選編程語言時,應該選擇最容易表達本身意圖的語言。理論上,能夠用任何語言編寫代碼,只要 編譯器是面向CLR的就能夠了。
 
編譯器
能夠視爲語法檢查器和「正確代碼」的分析器。它們檢查源代碼,肯定你寫的一切都有意義,而後輸出對你的意圖進行描述的代碼。不一樣的編程語言,有着不一樣的語法。不要低估這個選擇的價值,也許會節省大量的開發時間。
Microsoft已經建立好幾個面向「運行時」的語言編譯器,包括:C++/CLI、C# (C sharp)、Visual Basic、F#、Iron Python、Iron Ruby以及一個「中間語言」(Intermediate Language, IL)彙編器。
 
IL代碼 (託管代碼)
本地代碼編譯器是面向特定CPU架構的代碼。而每一個面向CLR的編譯器生成的都是 IL 代碼 (中間語言 代碼 。IL代碼有時稱爲 託管代碼,由於CLR要管理它的執行。它明顯的優點在於它是CPU無關的。
 
元數據
IL代碼由面向CLR的編譯器產生,但它並非編譯器產生的提供給運行時僅有的東西。編譯器一樣產生有關原始代碼的元數據。它提供給CLR關於代碼更多的東西,例如:各類類型的定義、各類類型成員的簽名以及其餘數據。基本上,元數據是類型庫、註冊表內容和其它用於COM的信息。儘管如此,元數據仍是直接和執行代碼合併在一塊兒,並不處在 隔離的位置。
簡單地說,元數據是整個microsoft .net framework開發平臺的關鍵,它實現了編程語言、類型和對象的無縫集成。
 
程序集 (assembly)
一個抽象的概念。首先,他是一個或多個模塊/資源文件的邏輯性分組。其次,程序集是重用、安全性以及版本控制的最小單元。取決於你對編譯器或者工具的選擇,便可以生成單文件程序集,也能夠生成多文件程序集。在CLR的世界中,程序集至關於一個「組件」。利用「程序集」這個概念性的東西,能夠將一組文件當成一個單獨的實體來對待。
對於一個可重用的、可保護的、可版本控制的組件,程序集把它的邏輯表示和物理表示分開。具體如何將代碼和資源劃分到不一樣的文件中,徹底取決於我的。程序集的模塊中,還包含與引用的程序集有關的信息。這些信息使程序集可以自描述(self-describing)。換句話說,CLR可以判斷出爲了執行程序集中代碼,程序集的直接依賴對象(immediate dependency)是什麼。
 
託管程序集同時包含 元數據IL。IL是與CPU無關的機器語言,是Microsoft在請教了外面的幾個商業及學術性語言/編譯器的做者以後,費勁心思開發出來的。IL比大多數CPU機器語言都要高級。IL能訪問和操做對象類型,並提供了指令來建立和初始化對象,調用對象上的虛方法以及直接操做數據元素。甚至能夠提供拋出和捕捉異常的指令來實現錯誤處理。可將 IL視爲一種面向對象的機器語言
 
重要的提示:
容許在不一樣編程語言之間方便地切換,同時又保持緊密集成,這事CLR的一個很是出色的特性。遺憾的是,許多開發人員都忽視了這一特性。例如,C#和Visual Basic等語言能不少地執行I/O操做,APL語言能很好地執行高級工程或者金融計算。經過CLR,應用程序的I/O部分可用C#編寫,工程計算部分則換用APL編寫。CLR在這些語言之間提供了其餘技術沒法媲美的集成度,使「混合語言編程」成爲許多開發項目的一個值得慎重考慮的選擇。
 
執行一個方法,首先必須把它的IL轉換成本地CPU指令,這是CLR的JIT (just-in-time或者「即時」)編譯器的職責。JITCompiler 是CLR的一個組件,稱爲JITer 或者JIT編譯器。它在定義(某一個類型)程序集的元數據中查找被調用的方位的IL, 接着驗證IL代碼,並將IL代碼編譯成本地CPU指令。本地CPU指令被保存到一個動態分配的內存塊中。
 
 
 
一個方法只有在首次調用時纔會形成一些性能損失。之後對該方法的全部調用都以本地代碼的形式全速運行,無需從新驗證IL並把它編譯成本地代碼。
 
JIT編譯器將本地CPU指令存儲到動態內存中,一旦應用程序終止,編譯好的代碼也會被丟棄。因此,若是未來再次運行應用程序,或者同時啓動應用程序的兩個實例(使用兩個不一樣的操做系統進程),JIT編譯器必須再次將IL編譯成本地指令。
對於大多數應用程序來講,因JIT編譯器形成的性能損失並不顯著。大多數應用程序都會反覆調用相同的方法。在應用程序運行期間,這些方法只會對性能形成一次性的影響。另外,在方法內部花費的時間頗有可能比花在調用方法上的時間多得多。
 
 
還須要特別注意的是:
CLR的JIT編譯器會對代碼進行優化,這相似於非託管的C++編譯器的後端所作的工做。一樣地,可能花費較多的時間來生成優化的代碼。優化以後的代碼將得到更加出色的性能。
非託管的飯嗎是針對一種具體的CPU平臺編譯的,一旦調用,代碼直接就能執行。可是在託管環境中,代碼的編譯是分紅兩個階段完成的。首先,編譯器遍歷源代碼,作儘量多的工做來生成IL代碼,而爲了真正的執行調用,這些IL代碼自己必須在運行時編譯成本地CPU指令,這須要分配更多的內存,並須要花費額外的CPU的時間。實踐確實代表,運行時發生的第二個編譯階段會影響性能,會分配動態內存。可是,Microsoft進行了大量性能優化的工做,將這些額外的開銷保持在最低限度。
 
IL和驗證
IL是基於棧的。因爲IL沒有提供操做寄存器的指令,因此人們能夠很容易的建立新的語言和編譯器,生成面向CLR的代碼。
IL指令仍是「無類型」(typeless)的。例如,IL提供了一個add指令,它的做用是將壓入棧的最後兩個操做數加到一塊兒。add指令不分32位和64位版本。
IL的亮點是它對底層CPU的抽象,但這並不是它的最大優點。IL提供的最大的優點在於應用程序的健壯性和安全性。將IL編譯成本地CPU指令時,CLR會執行一個名爲驗證(verification)的過程,這個過程會檢查高級IL代碼,肯定代碼所作的一切都是安全的。如,驗證會覈實調用的每一個方法多有正確數量的參數,傳給每一個方法的參數都具備正確的類型,每一個方法的返回值都獲得了正確的使用,每一個方法都具備一個返回語句等等。在託管模塊的元數據中,包含了要由驗證過程使用的全部方法和類型信息。
 
 
將每一個windows進程都放到一個獨立的地址空間,將得到健壯性和穩定性,一個進程沒法干擾另外一個進程。經過驗證 託管代碼,確保代碼不會不正確的訪問內存,不會干擾到另外一個應用程序的代碼。這樣一來,就能夠放心地將多個託管應用程序放到一個Windoes虛擬地址空間中運行。
CLR提供了在 一個操做系統進程中執行多個託管應用程序的能力。每一個託管的應用程序都在一個AppDomain中執行。默認狀況下,每一個託管的exe文件都在它本身的獨立地址空間中運行,這個地址空間只有一個AppDomain。然而,CLR的宿主進程(好比IIS或者MS SQL Server)  可決定在單個操做系統進程中運行多個AppDomain。
 
通用類型系統
CLR是徹底圍繞類型展開的,這一點到如今爲止應該很明顯了。類型爲應用程序和其餘類型公開了功能。經過類型,用一種編程語言寫的代碼能與另外一種語言寫的代碼溝通。因爲類型是CLR的根本,因此Microsoft指定了一個正式的規範,叫作「通用類型系統」(Common Type System, CTS), 描述類型定義和行爲。利用了CTS指定的規則,程序集爲一個類型創建了可視邊界,CLR則強制(貫徹)了這些規則。
 
事實上,並不須要去學習CTS規則本省,你選擇的語言會採用你熟悉的公式公開它本身的語言語法與類型規則。經過編譯來生成程序集時,它會將語言特有的語法映射到IL -- 也就是CLR的「語言」。
 
CLR讓咱們意識到:「代碼的語言」和「代碼的行爲」。不一樣語言能夠定義系統的類型,添加相同的成員,語法有不一樣,可是類型的行爲都是徹底一致的,由於最終由CLR的CTS來定義類型的行爲。
 
 
--------------------------------------------------------------------
 
相關文章
相關標籤/搜索