第三講 Microsoft.Net平台基礎構造
拋開Microsoft.NET平台去談C#是沒有意義的,C#之“Sharp”也正在其後端強大的平台。僅僅拘泥於語法層面是體驗不了C#的銳利之處的,C#程序很多詭秘之處必須依靠Microsoft.NET平台才能深度的掌握和運用。簡單的講,Microsoft.Net平台是一個建立在開放互聯網絡協議和標准之上,采用新的工具和服務來滿足人們的計算和通信需求的革命性的新型XML Web智能計算服務平台。它允許應用程序在因特網上方便快捷地互相通信,而不必關心使用何種操作系統和編程語言。
從技術層面具體來說,Microsoft.NET平台主要包括兩個內核,即通用語言運行時(Common Language Runtime,簡稱CLR)和Microsoft.NET框架類庫,它們為Microsoft.NET平台的實現提供了底層技術支持。通用語言運行時是建立在操作系統最底層的服務,為Microsoft.NET平台的執行引擎。Microsoft.NET框架包括一套可被用於任何編程語言的類庫,其目的是使得程序員更容易地建立基於網絡的應用和服務。在此之上是許多應用程序模板,這些模板為開發網絡應用和服務提供高級的組件和服務。Microsoft.Net平台之浩瀚絕非這裡的幾千字能夠廓清,我們下面將著重體驗那些對我們用C#開發應用程序至關重要的平台基礎構造。
通用語言運行時(CLR)
通用語言運行時是整個Microsoft.NET框架賴以建構的基礎,它為Microsoft.NET應用程序提供了一個托管的代碼執行環境。它實際上是駐留在內存裡的一段代理代碼,負責應用程序在整個執行期間的代碼管理工作,比較典型的有:內存管理,線程管理,安全管理,遠程管理,即時編譯,代碼強制安全類型檢查等。這些都可稱得上Microsoft.Net框架的生命線。
實際上我們可以看出來,CLR代理了一部分傳統操作系統的管理功能。在CLR下的代碼稱之為托管代碼,否則稱為非托管代碼。我們也可將CLR看作一個技術規范,無論程序使用什麼語言編寫,只要能編譯成微軟中間語言 (MSIL),就可以在它的支持下運行,這使得應用程序得以獨立於語言。目前支持CLR的編程語言多達二三十種。微軟中間語言是我們在Microsoft.NET平台下編譯器輸出的PE文件的語言。它是Microsoft.NET平台最完整的語言集,非常類似於PC機上的匯編語言。即時編譯器在運行時將中間語言編譯成本地二進制代碼。它為Microsoft.NET平台提供了多語言的底層技術支持。另外根據需要,Microsoft.Net即時編譯器提供了特殊情況下的經濟型即時編譯和安裝時編譯技術。
CLR的設計目的便是直接在應用程序運行環境中為基於組件的編程提供第一等的支持。正如在Windows中添加了對窗口、控件、圖形和菜單的直接支持,為基於消息的編程添加了底層結構,為支持設備無關性添加了抽象內容一樣,CLR直接支持組件(包括屬性和事件)、對象、繼承性、多態性和接口。對屬性和事件的直接支持使得基於組件的編程變得更簡單,而不需要特殊的接口和適配設計模式。在組件運行時,CLR負責管理內存分配、啟動和中止線程和進程、強化安全系數,同時還調整任何該組件涉及到的其他組件的附屬配置。序列化支持允許以多種格式操作存儲在磁盤上的組件,包括基於業界標准XML的SOAP。CLR提供了處理錯誤條件的有力、協調的方式。每個模塊都具有內置的完整的元數據,這意味著諸如動態創建和方法調用之類的功能更容易,也更安全。映射甚至允許我們靈活地創建和執行代碼。我們可以控制應用程序使用的組件的版本,這使應用程序更加可靠。組件代碼是與處理器無關的和易於驗證的中間語言 ( IL),而不是某一種特定的機器語言,這意味著組件不但可以在多種計算機上運行,而且可以確保組件不會覆蓋它們不使用的內存,也不會潛在地導致系統崩潰。CLR根據托管組件的來源(例如來自因特網,企業局域網,本地機)等因素對他們判定以適當的信任度,這樣CLR會根據他們的信任度來限定他們執行如讀取文件,修改注冊表等某些敏感操作的權限。借助通用類型系統(Common Type System,簡稱CTS)對代碼類型進行嚴格的安全檢查避免了不同組件之間可能存在的類型不匹配的問題。CLR下的編程全部是圍繞組件進行的。
值得指出的是CLR通常寄宿在其他高性能的服務器應用程序中,比如:因特網信息服務器(IIS),Microsoft SQL Server。這使得我們可以充分利用通用語言運行時諸多的安全,高效的優點來部署自己的商業邏輯。
內存管理
CLR對程序員影響最大的就是它的內存管理功能,以至於我們很有必要單獨把它列出來闡述。它為應用程序提供了高性能的垃圾收集環境。垃圾收集器自動追蹤應用程序操作的對象,程序員再也用不著和復雜的內存管理打交道。這在某些喜歡張口閉口底層編程的所謂的高手來說,自動內存管理從來都是他們嘲笑的對象。的確,為通用軟件環境設計的自動化內存管理器永遠都抵不上自己為特定程序量身訂制的手工制作。但現代軟件業早已不再是幾百行代碼的作坊作業,動辄成千上萬行的代碼,大量的商業邏輯凸現的已不再是算法的靈巧,而是可管理性,可維護性的工程代碼。.NET/C#不是為那樣的作坊高手准備的,C語言才是他們的尤物。在Microsoft.NET托管環境下,CLR負責處理對象的內存布局,管理對象的引用,釋放系統不再使用的內存(自動垃圾收集)。這從根本上解決了長期以來困擾軟件的內存洩漏和無效內存引用問題,大大減輕了程序員的開發負擔,提高了程序的健壯性。實際上我們在托管環境下根本找不到關於內存操作或釋放的語言指令。值得指出的是Microsoft.Net應用程序可以使用托管數據,也可以使用非托管數據,但CLR並不能判斷托管數據與非托管數據。
垃圾收集器負責管理.NET應用程序內存的分配和釋放。當用new操作符創建新的對象時,垃圾收集器在托管堆(Managed Heap)中為對象分配內存資源。只要托管堆內的內存空間可用,垃圾收集器就為每一個新創建的對象分配內存。當應用程序不再持有某個對象的引用,垃圾收集器將會探測到並釋放該對象。值得注意的是垃圾收集器並不是在對象引用無效時就立即開始釋放工作,而是根據一定算法來決定什麼時候進行收集和對什麼對象進行收集。任何一個機器的內存資源總是有限的,當托管堆內的內存空間不夠用時,垃圾收集器啟動收集線程來釋放系統內存。垃圾收集器根據對象的存活時間,對象歷經的收集次數等來決定對哪些對象的內存進行釋放。宏觀的看,我們並不知道垃圾收集的確切行為,但Microsoft.Net類庫為我們提供了控制垃圾收集行為的部分功能,在某些特殊情況下,我們有必要進行一些受限的操作。
垃圾收集器並不意味著程序員從此可以一勞永逸,如果正在操作一個包裝了如文件,網絡連接,Windows句柄,位圖等底層操作系統資源的對象,我們還是需要明確地釋放這些非托管資源的。這在“第五講 構造器與析構器”裡有詳細的闡述。