快速理解.NET Framework
引言
本文着眼於微軟.NET框架。這是較新發布的軟件開發環境,它幫助開發者快速開發應用程序並且提供各種不同語言像Visual Basic .NET, C#, ASP .NET, 和Jscript .NET等開發最合適的,高效的,可擴展的,面向性能的應用程序 。
.NET框架概述
.NET框架是一種新的計算平臺,它在Internet高度分佈的環境中簡化應用程序開發
服務
NET框架提供以下服務:
- 開發軟件應用工具
- 執行軟件應用的運行時環境
- 服務器基礎設施
- 幫助開發者減少編碼提高工作效率的增值只能軟件
.NET框架將使開發者爲不同設備和不同平臺開發應用程序,如:windows應用程序、web應用程序、windows服務和web服務。
目標
設計.NET框架是爲了實現下列目標:
- 一個一致的面向對象編程環境,目標代碼能本地化存儲和執行,本地化執行而不是分佈式Internet,或者遠程執行。
- 一個減少軟件部署和版本衝突的代碼編輯環境。
- 一個確保安全的代碼執行的代碼編輯環境,包括來自未知的或是不能完全信任的社團的代碼。
- 一個能消除腳本的或解釋性的環境引起的性能問題的代碼編輯環境。
- 開發者在面對大量不同應用系統類型時有一致的開發體驗,如基於Windows的應用程序和基於Web的應用程序。
- 構造所有工業標準信息來確保基於.NET框架的代碼能夠集成任何其他代碼。
理解.NET框架體系結構
.NET框架有兩個組件:.NET框架類庫和公共語言運行時。
.NET框架類庫使類型(CTS)變的簡單,它對於.NET語言來說是公共的。
公共語言運行時組成部分有由:(類加載器)加載程序的IL代碼並將起編譯成本地代碼到運行時,執行和管理代碼來加強安全和類型安全,並且提供線程支持。
.NET框架體系結構最頂部是像VB .NET C#, VJ#, VC++ .NET之類的語言;開發者能開發(使用上面的任何語言)像Windows窗體,Web窗體,Windows服務和XML Web服務。
理解.NET框架的角色
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
.NET框架有兩個組要的組件:公共語言運行時(CLR)和.NET框架類庫。公共語言運行時是.NET框架的基礎。CLR 在運行時管理代碼,提供像內存管理,線程管理和remoting之類的核心服務,同時也加強嚴格的類型安全和促進代碼正確來確保程序的安全性和健壯性(魯棒性)。代碼管理的概念是CLR的基本原則。針對CLR的代碼被認爲是可管理的代碼,而不是針對CLR的代碼則被認爲是不可管理的代碼。
類庫是.NET框架的一個完整的組件, 包括可重用類的面向對象集合,它使我們能用來開發應用程序包括傳統的命令行或是任何像Windows窗體,ASP. NET Web窗體和新近發明的XML Web 服務的Windows服務這樣的圖形用戶接口(GUI)。
歐洲計算機制造商協會(ECMA)標準定義了通用語言規範(CLS);這加強了軟件開發語言能夠進行互操作。按照CLS編寫的代碼應該能和另一個符合CLS語言的代碼一起編譯。因爲由符合CLS語言支持的代碼將會被編譯成中間語言(IL)代碼。CLR引擎執行IL代碼。這保證了符合CLS語言的互用性。微軟.NET框架支持的語言有Microsoft Visual Basic .NET, Microsoft Visual C#, Microsoft Visual C++ .NET, and Microsoft Visual J# .NET.
語言編譯器生成中間語言代碼,叫做微軟中間語言(MSIL),它使不同可互操作的.NET語言編寫程序。
ECMA標準,公共語言架構(CLI),定義了IL代碼需要執行的基礎架構的規範。CLI提供一個公共類型系統(CTS)和像類型安全,可管理的代碼執行和side by side執行的服務。
圖1.微軟.NET框架的ECMA標準
.NET框架提供基礎架構和服務。CLI規範.它們包括:
公共語言運行時:
CLR包括CLI
CLR也提供.NET應用程序的執行環境
公共類型系統:
提供數據類型,值,對象類型。這使得開發人員能用不同的語言開發應用程序。.NET語言共享CTS意味着所有在應用程序中的類型在CLI類型定義中是一樣的。
類型安全:
.NET框架在值和對象上執行操作,因爲.NET框架需要知道每個值和對象的類型並且引用值和對象類型。
可管理的代碼執行
.NET框架管理執行.NET應用程序時對象的狀態。
.NET框架自動分配內存並提供來機收集機制來重新分配內存
Side-by-side執行
.NET框架通過使用不同版本的裝配器允許同一應用程序的不同版本運行在同一機器上。裝配器由IL代碼和元數據組成。元數據決定應用程序的依賴關係。通過這個,.NET框架運行時能執行多種版本裝配器並且解決遺留的開發環境的主要問題。那就是DLL HELL?
.NET裝配器
圖2 Side-by-side執行
理解.NET框架CLR
公共語言運行時:
- 運行時環境
- CLR把應用程序編譯成有運行時,把IL代碼編譯成本地代碼,執行代碼
- 運行時服務
- 內存管理
- 類型安全
- 增強安全
- 異常管理
- 線程支持
- 調試支持
- 類加載器,將類加載到CLR。
- MSIL到本地代碼的編譯,將把MSIL轉變成本地代碼。
- 代碼管理器,它在代碼執行期間進行管理。
- 內存分配和垃圾收集,表現爲自動內存管理。
- 安全的引擎,使用微軟提供的工具和在控制面板對.NET框架配置加強安全限制包括代碼級安全、文件及機器級安全。
- 類型檢查器,增強強類型檢查。
- 線程支持,提供對應用程序的多線程支持。
- 異常管理器,提供對運行時異常處理的機制。
- 調試引擎,允許開發者調試應用程序的不同類型。
- COM配置,允許.NET應用程序與COM應用程序交換數據。
- 基類庫支持,提供應用程序運行時所需的類。
公共語言運行時的特徵
CLR有以下特徵:
- 管理內存:
- 內存分配
- 內存的重分配(垃圾收集)
- 線程執行支持
- 代碼執行
- 代碼安全檢查
- 編譯
- MSIL到本地代碼
- 基於信任的代碼安全(對執行代碼的授權。代碼級,文件級,機器級)這些特徵對運行在公共語言運行時的可管理代碼來說是固有的。
理解CLR
爲了執行程序並且獲得可管理執行環境的所以好處,我們用CLS支持的.NET框架語言編寫代碼。語言編譯器將源代碼編譯成由CPU相關的代碼和平臺相關的指令組成的MSIL代碼。MSIL有下列組成:
- 能夠執行算術和邏輯運算的指令。
- 直接訪問內存。
- 控制執行流
- 處理異常
MSIL代碼能夠在執行前被編譯成特定CPU指令,CLR所需要代碼的信息只有元數據。元數據描述代碼並且定義代碼類型包括引用代碼在運行期用到的其他類型。
一個裝配器由精簡的可執行文件組成。當執行PE文件的時候類加載器價載MSIL代碼而元數據把精簡的可執行文件編成運行時內存。
PE文件執行之前它將代碼傳遞到本地代碼編譯器進行編譯,IL到本地代碼的編譯是有JIT編譯器完成的。因爲不同的CPU架構和編譯器 IL代碼到本地指令。
CLR的特點
- 被管理的多線程支持和線程監控。應用程序域包括一個或多個執行線程。
- 管理不安全代碼的互用性,和COM配置。
- 結構化的異常處理機制
- 基礎架構和被管理執行進程,內存管理和垃圾收集
CLR的結構
- 基類庫支持支持所有使用.NET語言來支持基本功能性的基類。
- COM配置支持COM對象間數據的重組。
- 異常管理支持使用try catch finally語句塊在運行時處理錯誤。
- 安全引擎在運行時加強安全規則。
- 類型檢查器在運行時作類型安全檢查。
- 調試引擎支持運行時調試。
- 代碼管理器管理運行時被管理代碼
- IL到本地代碼編譯器將MSIL代碼編譯成機器相關的本地代碼
- 垃圾收集器支持內存管理並支持清理運行時廢棄的內存。
- 類加載器在運行時加載類。
JIT編譯器作爲CLR的一個完整的部分將MSIL代碼編譯成本地代碼並且實時執行整批代碼。代碼將會被緩存而下次就會從緩存中讀取代碼再次編譯執行(翻譯不出來)
JIT執行進程
CLR類加載器加載MSIL代碼並且將元數據加載到內存;代碼管理器調用WinMain或DllMain方法。JIT編譯器在其入口方法執行之前編譯這個方法。代碼管理器將對象放置在內存中並控制代碼的執行。垃圾收集器實現對管理堆的週期性檢查識別應用程序的無效對象。
程序執行時類型檢查器確保所有對象和值以及對象和值的引用有其合法的類型。類型檢查器也保證代碼的唯一合法操作,否則就拋出異常。代碼在運行時由CLR控制。CLR在以下行爲上增強安全性:
- 像硬盤一樣控制和訪問系統資源
- 控制和訪問網絡連接
- 控制和訪問其他硬件資源
被管理代碼執行被認爲是由CLR執行的進程,具體有以下幾個方面:
- CLR加載MSIL和應用元數據
- CLR執行本地代碼,
- CLR提供自動內存管理
- 被管理的執行也實現JIT編輯
- 封裝類型安全,
- 增強安全性
- 處理異常
被管理的執行進程
- 被管理代碼是自解釋性的代碼,它在.NET框架中給CLR多運行時服務的信息。
- 這些信息在PE文件裏以元數據的形式被存儲在MSIL代碼中。元數據信息會描述代碼包含的類型。
- 被管理數據是由垃圾收集器自動被分配和釋放的。被管理代碼能被被管理數據理解而非管理數據能被被管理理解。(翻的不正確)
內存管理
- 自動內存管理意味着當對象創建時不需要編寫代碼分配內存或是當應用程序不需要對象時釋放內存。
- 自動內存管理的進程包括下列任務:
?分配內存
- 當一個進程被初始化時,運行時保留了一個連續的地址空間而不爲它分配任何存儲空間。
- 這個保留的地址空間被叫做託管堆。託管堆在下一個對象被放置的地方保留了一個指針。
- 當一個應用程序使用new操作符創建一個對象時,new操作符檢查堆內對象所需的內存是否可用。
- 當下一個對象創建的時候,垃圾收集器在託管堆分配內存給對象。
- 在託管堆分配內存給對象的時間比分配非託管堆內存耗時要少。
- 在非託管堆中,指向內存的指針在鏈表數據結構中維護。因此,分配內存需要通過操縱鏈表,尋找能夠容納它的較大的內存塊。(此處原文不全)
- 與訪問非託管內存相比你能更快地訪問託管內存的對象,因爲在託管內存分配時,對象總是在託管的地址空間中分配。
?釋放內存
- 垃圾收集器週期性地應用程序不再需要的對象中釋放內存。
- 每個應用程序有一組根指針。根指針指向在託管堆存儲位置。每個根指針或者引用託管堆中的一個對象或是被置成空。
- 一個應用程序的根指針由線程棧上的全局靜態指針,局部變量和引用對象參數組成。
- JIT編譯器和運行時維護應用程序根指針的列表。垃圾收集器使用這個列表創建從根指針列表中獲得的在託管堆中的對象圖表。
- 當垃圾收集器開始運行,它把在託管堆中的所有對象都看作垃圾。
- 垃圾收集器通過應用程序的根指針列表操作,這個列表定義了在應用程序根指針列表中有相應的引用的對象並對可獲得的對象標記。
- 垃圾收集器也把這樣的對象作爲可獲得對象。(不知道是什麼意思)
- 垃圾收集器認爲所有託管堆中不可獲得的對象是垃圾。
- 垃圾收集器通使用收集進程釋放垃圾對象空間。
- 垃圾收集器使用內存複製功能來壓縮託管堆中的對象。
- 垃圾收集器更新應用程序根指針列表中的指針,使得指向較早的應用程序根指針正確指向對象。
- 垃圾收集器使用高度優化的機制完成垃圾收集。它把託管堆中的對象分爲三級:0、1、和2。第0級包括最近被創建的對象。
- 垃圾收集器開始在第0級收集不可獲得的對象。接着,垃圾收集器緊縮內存並將可獲得對象提升爲第1級。
- 倖免於收集進程收集的對象被提升爲更高的級別。
- 垃圾收集器在第1級和第2級搜索不可獲得的對象,僅當通過第0級對象的收集進程釋放的內存不足以創建一個新的對象時。
- 垃圾收集器爲所有應用程序創建的託管對象管理內存。
- 垃圾收集器能通過在對象等Dispose方法中提供清除代碼來顯式釋放這些系統資源。
- 我們在對象完成工作後需要顯式調用Dispose方法。
?實現完成器
- 完成器進程允許一個對象在垃圾收集器啓動之前完成清理工作。
- Finalize方法確保了即使客戶沒有顯式調用Dispose方法,所使用的資源在對象被垃圾收集時也會從內存被釋放。
- 在垃圾收器集進行垃圾收集時識別對象是垃圾後,它在釋放內存前調用對象的Finalize方法。
- 完成器是包含在對象收集之前被執行的清理代碼的方法。執行清理代碼的進程被叫做終結。Dispose和Finalize方法被叫做完成器。
- 對象的Dispose方法會釋放所有資源,包括它的父對象擁有的資源通過調用父對象的Dispose方法。
- 我們有兩個方法執行Dispose方法:
- 類用戶能夠調將被銷燬對象的Dispose方法,或者
- Finalize方法能在終結過程中調用Dispose方法。