公共語言運行庫(CLR)

公共語言運行庫(CLR)

概述

.NET Framework的核心是其運行庫的執行環境,稱爲公共語言運行庫(CLR)或.NET運行庫.通常將在CLR的控制下運行的代碼稱爲託管代碼(managed code).

但是,在CLR執行編寫好的源代碼之前,需要編譯它們(在C#中或其它語言中).在.NET中,編譯分爲兩個階段:

1、把源代碼編譯爲Microsoft中間語言(IL)。

2、CLR把IL編譯爲平臺專用的代碼。

這個兩階段的編譯過程非常重要,因爲Microsoft中間語言(託管代碼)是提供.NET的許多優點的關鍵.

 

.NET平臺的整體結構:

.NET平臺的整體結構

NET Framework是架構在Windows平臺上的一個虛擬的運行平臺,你可以想象將最下層Windows換做其他的操作系統,例如說Linux,一樣可以實現使用符合CLS(Common Language Specification,通用語言規範)的.NET語言,(VB.NET、C#、JScript.NET等),來創建ASP.NET或Windows Form(可能會叫Linux Forms)應用程序的功能,這其實就是Mono計劃要實現的功能。所以可以這麼認爲,理論上,C#是一種可以跨平臺的語言,這很象Java。C#另一個比較象Java的地方是,它也是一種(特殊意義上的)語言,同Java一樣,C#編寫的程序代碼也是先通過C#編譯器編譯爲一種特殊的字節代碼, (Microsoft Intermediate Language,MSIL,微軟)中間語言,運行時再經由特定的編譯器(JIT編譯器,Just In tIME,  JITer)編譯爲機器代碼,以供操作系統執行.
不僅是C#語言,所有.NET語言(將會包括我們常用的幾十種現代的編碼語言)都可以編寫面向CLR的程序代碼,這種代碼在.NET中被稱爲託管代碼(Managed Code),所有的Managed Code都直接運行在CLR上,具有與平臺無關的特性。

解釋性的語言很安全,並且可以通過他的運行平臺爲其賦予更多的功能,例如自動內存管理,異常處理等.

 

CLR結構圖

CLR結構圖

C#所具有的許多特點都是由CLR提供的,如類型安全(Type Checker)、垃圾回收(Garbage Collector)、異常處理(Exception Manager)、向下兼容(COM Marshaler)等,具體的說,.NET上的CLR爲開發者提供如下的服務:
1、平臺無關:CLR實際上是提供了一項使用了虛擬機技術的產品,他構架在操作系統之上,並不要求程序的運行平臺是 Windows系統,只要是能夠支持它的運行庫的系統,都可以在上面運行.NET應用。所以,一個完全由託管代碼組成的應用程序,只要編譯一次,就可以在任何支持.NET的平臺上運行.
2、跨語言集成:CLR語序開發這以任何語言進行開發,用這些語言開發的代碼,可以在CLR環境下緊密無縫的進行交叉調用,例如,可以用VB聲明一個基類對象,然後在C#代碼中直接創建次基類的派生類。
3、自動內存管理:CLR提供了拉架收集機制,可以自動管理內存。當對象或變量的生命週期結速後,CLR會自動釋放他們所佔用的內存.
4、跨語言應用

當編程人員在用自己喜歡的編程語言寫源代碼的時候, 這個源代碼在被轉化成媒介語言(IL)之前,先被編譯成了一個獨立的可執行單元(PE)。這樣無論 你是一個VB。NET程序員,或一個C#程序員,甚至是使用託管的C++的程序員。只要被編譯成IL就是同等的。 首先,編譯輸出的exe是一個由中間語言(IL),元數據(Metadata)和一個額外的被編譯器添加的目標平臺的標準可執行文件頭(比如Win32平臺就是加了一個標準Win32可執行文件頭)組成的PE(portable executable,可移植執行體)文件,而不是傳統的二進制可執行文件--雖然他們有着相同的擴展名。中間語言是一組獨立於CPU的指令集,它可以被即時編譯器Jitter翻譯成目標平臺的本地代碼。中間語言代碼使得所有Microsoft.NET平臺的高級語言C#,VB.NET,VC.NET等得以平臺獨立,以及語言之間實現互操作。元數據是一個內嵌於PE文件的表的集合。
5、版本控制

由於使用了元數據,所以你可以使用XCOPY簡單的複製就可以了,而CLR也可以在運行時期讀取元數據,以確保多版本程序運行在同一進程中。使用公共語言運行庫的程序集的所有版本控制都在程序集級別上進行。一個程序集的特定版本和依賴程序集的版本在該程序集的清單中記錄下來。除非被配置文件(應用程序配置文件、發行者策略文件和計算機的管理員配置文件)中的顯式版本策略重寫,否則運行庫的默認版本策略是,應用程序只與它們生成和測試時所用的程序集版本一起運行。
6、.NET安全

.NET提供了一組安全方案。負責進行代碼的訪問安全性檢查。允許我們對保護資源和操作的訪問。代碼需要經過身份確認和出處鑑別後才能得到不同程度的信任。安全策略是一組可配置的規則,公共語言運行庫在決定允許代碼執行的操作時遵循此規則。安全策略由管理員設置,並由運行庫強制。運行庫確保代碼只能訪問安全策略允許的資源和調用安全策略允許的代碼。 每當發生加載程序集的嘗試時,運行庫就使用安全策略確定授予程序集的權限。在檢查了描述程序集標識的信息(稱爲證據)後,運行庫使用安全策略決定代碼的信任程度和由此授予程序集的權限。證據包括但不僅限於代碼的出版商、它的站點以及它的區域。安全策略還確定授予應用程序域的權限。
7、簡單的組件互操作性。
8、自描述組件:
自描述組件是指將所有數據和代碼都放在一個文件中的執行文件。自描訴組件可以大大簡化系統的開發和配置,並且改進系統的可靠性。

通用語言運行時(CommonLanguageRuntiome,CLR)最早被稱爲下一代Windows服務運行時(NGWS Runtime).它是直接建立在操作系統上的一個虛擬環境,主要的任務是管理代碼的運行。CLR現在支持幾十種現代的編程語言爲它編寫代碼,然後以一種中間語言(Intermediate Langeoage,IL)代碼的形成被執行。並且,CLR還提供了許多功能以簡化代碼的開發和應用配置,同時也改善了應用程序的可靠性。如你所知,如果某種語言的編譯器是以運行時爲目標的,那麼利用該語言開發生成的代碼在.NET中被稱爲託管代碼,因爲這樣的代碼是直接運行在CLR上的,所以具有與平臺無關的特點。

在.NET平臺結構圖中,CLR的上面是.NET的基類庫,這組基類庫包括從基本輸入輸出到數據訪問等各方面,提供了一個統一的面向對象的,層次化的,可擴展的編程接口。從.NET平臺結構圖中也可以看到,基類庫可以被各種語言調用和擴展,也就是說不管是 C#,VB.NET還是VC++.NET,都可以自由的調用,.NET的類庫,因爲C#自身只有77個關鍵字,而且語法對程序員來說無需費工夫學習。 BCL則相反,它包含了4500個以上的類和無數的方法,屬性,在你的C#程序中隨時都可能會用到它來完成自己的任務.

還有一個很重要的概念你需要明白,這就是公共語言架構(Common Language Infrastructure,CLI).CLI是CLR的一個子集,也就是.NET中最最終對編譯成MSIL代碼的應用程序的運行環境進行管理的那一部分。在CLR結構圖中CLI位於下半部分,主要包括類加載器(Class Loader)、實時編譯器(IL To Native Compilers)和一個運行時環境的垃圾收集及將使用任何語言編寫的代碼,通過其特定的編譯器轉換爲MSIL代碼之後運行其上,甚至還可以自己寫 MSIL在CLI上運行.

9、調用和配置

當運行庫試圖解析對另一個程序集的引用時,就開始進行定位並綁定到程序集的進程。該引用可以是靜態的,也可以是動態的。在生成時,編譯器在程序集清單的元數據中記錄靜態引用。動態引用是由於調用各種方法而動態構造的,例如 System.Reflection.Assembly.Load 方法。 引用程序集的首選方式就是使用完全引用,包括程序集名稱、版本、區域性和公鑰標記(如果存在)。運行庫就會使用這些信息來定位程序集。無論引用是對靜態程序集的引用還是對動態程序集的引用,運行庫均使用相同的解析過程。 還可通過向調用方法僅提供有關程序集的部分信息的方式(例如僅指定程序集名稱),對程序集進行動態引用。在這種情況下,僅在應用程序目錄下搜索程序集,不進行其他檢查。您可以使用不同加載程序集方法中的任何方法(例如 System.Reflection.Assembly.Load 或 AppDomain.Load)進行部分引用。如果希望運行庫在全局程序集緩存和應用程序目錄下檢查引用的程序集,可以用 System.Reflection.Assembly.LoadWithPartialName 方法指定部分引用。 最後,可以使用諸如 System.Reflection.Assembly.Load 之類的方法進行動態引用並只提供部分信息;然後在應用程序配置文件中用 <qualifyAssembly> 元素限定該引用。該元素使您可以在應用程序配置文件中而不是在代碼中提供完全引用信息,包括名稱、版本、區域性和公鑰標記(如果適用)。如果要在應用程序目錄外完全限定對某個程序集的引用,或者如果要引用全局程序集緩存中的程序集,但又希望方便地在配置文件中而不是在代碼中指定完全引用,就可以採用這一技術。

10、GC

一個跟蹤過程,它傳遞性地跟蹤指向當前使用的對象的所有指針,以便找到可以引用的所有對象,然後重新使用在此跟蹤過程中未找到的任何堆內存。公共語言運行庫垃圾回收器還壓縮使用中的內存,以縮小堆所需要的工作空間。 垃圾收集器的基本算法很簡單: ● 將所有的託管內存標記爲垃圾 ● 尋找正被使用的內存塊,並將他們標記爲有效 ● 釋放所有沒有被使用的內存塊 ● 整理堆以減少碎片

 

CLR的基本特性

1、與本機代碼無關 ——— MSIL (中間語言)

2、讓我們使用同一種語言 ——— CLR (公共語言運行時)

3、我們手中的零件 ——— Assembly (裝配件)

4、讓我們在同一個系統中運行 ——— CTS (通用類型系統)

5、宇宙大爆炸後的產物 ——— metadata (元數據)

6、讓我們的語言可以交流 ——— CLS (公共語言系統)

7、在動態中交互 ——— Reflection (反射)

8、屬於我們自己的空間 ——— NameSpace (名稱空間)

 

 

MSIL:微軟中間語言

Reflection:反射

Metadata:元數據

PE:可執行可移植文件

Assembly: 程序集(裝配件)

NameSpace:名稱空間

CTS:通用類型系統

GC(Garbage Colection) :無用單元回收

CLR:公共語言系統

Attribute:屬性(注意不要和Property混淆)

Boxing: 裝箱

UnBoxing: 拆箱

 

MSIL 使用.NET支持的語言所編寫的代碼 

MSIL(Microsoft Intermediate Language)微軟的中間語言。和JAVA的虛擬機類似,是與CPU無關的指令集。當編譯爲託管代碼時,編譯器將源代碼翻譯爲MSIL, 如上圖所示。MSIL 包括用於加載、存儲和初始化對象以及對對象調用方法的指令,還包括用於算術和邏輯運算、控制流、直接內存訪問、異常處理和其他操作的指令。在可以執行代碼前,必須將 MSIL 轉換爲 CPU 特定的代碼,這通常是通過實時 (JIT) 編譯器完成的。由於公共語言運行庫爲它支持的每種計算機結構都提供了一種或多種 JIT 編譯器,因此可以在任何受支持的結構上對同一組 MSIL 進行 JIT 編譯和執行。這樣總結上面的就是:中間語言是一組獨立於CPU的指令集,它可以被即時編譯器Jitter翻譯成目標平臺的本地代碼。

 

PE

Windows PE和一個 .NET PE的主要區別在於Windows PE 是由操作系統執行的,而.NET PE 卻被轉變成爲.NET Framework的CLR. 識別一個PE是 .NET還是Windows取決於他的通用的目標文件格式 (COFF) 是否使用Windows的操作系統. 目標文件格式 (COFF) 指定了任何文件都分成兩個部分:文件數據本身以及描述文件內包含的數據內容的頭文件串。 MSIL 彙編程序從 MSIL 彙編語言生成可移植可執行的 (PE) 文件。可以運行結果可執行文件(該文件包含 MSIL 和所需的元數據)以確定 MSIL 是否按預期執行。這就是我爲什麼會談到PE。

那麼PE文件是怎麼執行的呢?下面是一個典型的.NET應用程序的執行過程:

1.用戶執行編譯器輸出的應用程序(PE文件),操作系統載入PE文件,以及其他的DLL(.NET動態連接庫)。
2.操作系統裝載器根據PE文件中的可執行文件頭跳轉到程序的入口點。顯然,操作系統並不能執行中間語言,該入口點也被設計爲跳轉到mscoree.dll(.NET平臺的核心支持DLL)的_ CorExeMain()函數入口。
3.CorExeMain()函數開始執行PE文件中的中間語言代碼。這裏的執行的意思是CRL(通用語言運行時)按照調用的對象方法爲單位,用JIT(即時編譯器)將中間語言編譯成本地機二進制代碼,執行並根據需要存於機器緩存。
4.程序的執行過程中,GC(垃圾收集器)負責內存的分配,釋放等管理功能。
5.程序執行完畢,操作系統卸載應用程序。

 

.NET Framework 環境

下面的插圖顯示公共語言運行時和類庫與應用程序之間以及與整個系統之間的關係。該插圖還顯示託管代碼如何在更大的結構內運行。

 

公共語言運行時(CLR)的功能

       公共語言運行時管理內存、線程執行、代碼執行、代碼安全驗證、編譯以及其他系統服務。這些功能是在公共語言運行時上運行的託管代碼所固有的

  • 至於安全性,取決於包括託管組件的來源(如 Internet、企業網絡或本地計算機)在內的一些因素,託管組件被賦予不同程度的信任

  • 運行時強制實施代碼訪問安全。例如,用戶可以相信嵌入在網頁中的可執行文件能夠在屏幕上播放動畫或唱歌,但不能訪問他們的個人數據、文件系統或網絡。這樣,運行時的安全性功能就使通過 Internet 部署的合法軟件能夠具有特別豐富的功能。

  • 運行時還通過實現稱爲常規類型系統 (CTS) 的嚴格類型驗證和代碼驗證基礎結構來加強代碼可靠性。CTS 確保所有託管代碼都是可以自我描述的。各種 Microsoft 編譯器和第三方語言編譯器都可生成符合 CTS 的託管代碼。這意味着託管代碼可在嚴格實施類型保真和類型安全的同時使用其他託管類型和實例。

  • 此外,運行時的託管環境還消除了許多常見的軟件問題。例如,運行時自動處理對象佈局並管理對對象的引用,在不再使用它們時將它們釋放。這種自動內存管理解決了兩個最常見的應用程序錯誤:內存泄漏和無效內存引用。

  • 運行時還提高了開發人員的工作效率。例如,程序員可以用他們選擇的開發語言編寫應用程序,卻仍能充分利用其他開發人員用其他語言編寫的運行時、類庫和組件。任何選擇以運行時爲目標的編譯器供應商都可以這樣做。以 .NET Framework 爲目標的語言編譯器使得用該語言編寫的現有代碼可以使用 .NET Framework 的功能,這大大減輕了現有應用程序的遷移過程的工作負擔。

  •   儘管運行時是爲未來的軟件設計的,但是它也支持現在和以前的軟件。託管和非託管代碼之間的互操作性使開發人員能夠繼續使用所需的 COM 組件和 DLL。
  • 運行時旨在增強性能。儘管公共語言運行時提供許多標準運行時服務,但是它從不解釋託管代碼。一種稱爲實時 (JIT) 編譯的功能使所有託管代碼能夠以它在其上執行的系統的本機語言運行。同時,內存管理器排除了出現零碎內存的可能性,並增大了內存引用區域以進一步提高性能。
  • 最後,運行時可由高性能的服務器端應用程序(如 Microsoft® SQL Server™ 和 Internet 信息服務 (IIS))承載。此基礎結構使您在享受支持運行時承載的行業最佳企業服務器的優越性能的同時,能夠使用託管代碼編寫業務邏輯。

 

公共語言運行時(CLR)細節

  • 若要使公共語言運行時能夠向託管代碼提供服務,語言編譯器必鬚生成一些元數據來描述代碼中的類型、成員和引用。元數據與代碼一起存儲;每個可加載的公共語言運行時可遷移執行 (PE) 文件都包含元數據。公共語言運行時使用元數據來完成以下任務:查找和加載類,在內存中安排實例,解析方法調用,生成本機代碼,強制安全性,以及設置運行時上下文邊界。
  • 公共語言運行時自動處理對象佈局並管理對象引用,當不再使用對象時釋放它們。按這種方式實現生存期管理的對象稱爲託管數據。垃圾回收消除了內存泄漏以及其他一些常見的編程錯誤。如果您編寫的代碼是託管代碼,則可以在 .NET Framework 應用程序中使用託管數據、非託管數據或者同時使用這兩種數據。由於語言編譯器會提供自己的類型(如基元類型),因此您可能並不總是知道(或需要知道)這些數據是否是託管的。
  • 有了公共語言運行時,就可以很容易地設計出對象能夠跨語言交互的組件和應用程序。也就是說,用不同語言編寫的對象可以互相通信,並且它們的行爲可以緊密集成。例如,可以定義一個類,然後使用不同的語言從原始類派生出另一個類或調用原始類的方法。還可以將一個類的實例傳遞到用不同的語言編寫的另一個類的方法。這種跨語言集成之所以成爲可能,是因爲基於公共語言運行時的語言編譯器和工具使用由公共語言運行時定義的常規類型系統(CTS),而且它們遵循公共語言運行時關於定義新類型以及創建、使用、保持和綁定到類型的規則。
  • 所有託管組件都帶有生成它們所基於的組件和資源的信息,這些信息構成了元數據的一部分。公共語言運行時使用這些信息確保組件或應用程序具有它需要的所有內容的指定版本,這樣就使代碼不太可能由於某些未滿足的依賴項而發生中斷。註冊信息和狀態數據不再保存在註冊表中(因爲在註冊表中建立和維護這些信息很困難)。取而代之的是,有關您定義的類型(及其依賴項)的信息作爲元數據與代碼存儲在一起,這樣大大降低了組件複製和移除任務的複雜性。
  • 語言編譯器和工具公開公共語言運行時的功能的方式對於開發人員來說不僅很有用,而且很直觀。這意味着,公共語言運行時的某些功能可能在一個環境中比在另一個環境中更突出。您對公共語言運行時的體驗取決於所使用的語言編譯器或工具。例如,如果您是一位 Visual Basic 開發人員,您可能會注意到:有了公共語言運行時,Visual Basic 語言的面向對象的功能比以前多了。

.NET Framework 類庫

  • .NET Framework 類庫是一個與公共語言運行時緊密集成的可重用的類型集合。該類庫是面向對象的,並提供您自己的託管代碼可從中導出功能的類型。這不但使 .NET Framework 類型易於使用,而且還減少了學習 .NET Framework 的新功能所需要的時間。此外,第三方組件可與 .NET Framework 中的類無縫集成。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章