《.net編程先鋒C#》第二章 理論基礎-公用語言 運行環境(轉)

來源:互聯網
上載者:User
編程 第二章 理論基礎-公用語言 運行環境
既然你已經具有了C#全面的印象,我也想讓你瞭解NGWS runtime的全貌。C#依靠由NGWS提供的運行時;因此,有必要知道運行時如何工作,以及它背後所蘊含的概念。
所以,這一章分為兩部分——它們是所有的概念和使用的基礎。兩部分的內容雖然有些重疊,但它有助於加深理解正在學習的概念。

2.1 NGWS Runtime
NGWS和NGWS Runtime為你提供了一種運行時環境。該運行時管理執行代碼,並提供了使編程更容易的服務。只要你的編譯器支援這種運行時,你就會從這種受管理的執行環境中得益。
你猜測C#編譯器支援NGWS runtime很正確,但是不僅它支援NGWS runtime,VB和C++也支援。這些為支援運行時所建立的代碼稱作"受管代碼"(managed code)。以下是你的應用程式從NGWS runtime那裡所得到的利益:

交叉語言整合(通過通用語言規範)
自動記憶體管理(垃圾收集)
交叉語言異常處理(統一展開)
增強安全(包括型別安全)
版本支援("DLL地獄"終結者)
組件互動簡化模式

因NGWS runtime 要提供了所有的這些好處,編譯器必須把元檔案和受管代碼一起發出。元檔案描述代碼中的類型,它和你的代碼存在一起(與PE類似---PE為可變位執行檔案)
正如你從很多種交叉語言功能所看到的,NGWS runtime主要是關於高度整合交叉多異程式設計語言(tight integration across multiple different programming languages)。這種支援可達到允許你從一個VB對象派生出一個C#類的程度(我後面會給出要討論的文章)。
C#程式員將會喜歡的一個功能是,他們不必擔心記憶體管理—也就是說不必擔心臭名昭著的記憶體流失。NGWS runtime提供了記憶體管理,當對象和變數的生命期結束(不再被引用)時,垃圾收集器釋放它們。我真的喜歡這個功能,因為在COM中的記憶體管理一直是我的一塊心病。
應該鼓勵配置一個管理應用程式或者組件。因為管理應用程式含有中繼資料檔案,NGWS runtime可以利用這些資訊,以確保你的應用程式具有它所需的各種規定版本。所產生的明顯效果為,由於你的代碼沒有相互之間的依賴,很少可能出現中斷。
這章餘下來的將分為兩部分,每一部分討論NGWS runtime的各個方面,直到你的C#應用程式能執行為止。
1、中繼語言(Intermediate Language,縮寫IL)和中繼資料
2、即時編譯器(just-in-time compliers,簡稱JITers)

2.1.1 中繼語言和中繼資料
由C#編譯器產生的受管代碼並不是原始代碼,但它是中繼語言(IL)代碼。這種IL代碼自身變成了NGWS runtime的受管執行進程的入口。IL代碼明顯的優勢在於它是CPU無關的,這也意味著,你要用目標機器上的一個編譯器才能把IL代碼轉換成原始代碼。
儘管IL代碼由編譯器產生,但它並不是編譯器提供給運行時僅有的東西。編譯器同樣產生有關你代碼的中繼資料,它告訴運行時有關你代碼的更多的東西,例如各種類型的定義、各種類型成員的簽名以及其它資料。基本上,中繼資料是類型庫、註冊表內容和其它用於COM的資訊。儘管如此,中繼資料還是直接和執行代碼合并在一起,並不處在隔離的位置。
IL和中繼資料存放於擴充了PE格式的檔案中(PE格式用於.exe和.dll檔案)。當這樣的一個PE檔案被裝載時,運行時從檔案中定位和分離出中繼資料和IL。
在進一步說明之前,我想給你已有的IL指令的簡短目錄。儘管它不是一個完整的清單,也不需要你熟記和理解,但是它列出了你所必需的、C#程式所基於的知識基礎。

算術和邏輯操作符
控制流程
直接記憶體存取
堆棧操作
參數和局部變數
堆棧分配
對象模式
執行個體類型值
臨界區
數組
分型位置
即時編譯器(JITters)

2.1.2 即時編譯器(JITters)
由C#或其它能產生受管代碼的編譯器所產生的受管代碼就是IL碼。雖然IL代碼被封裝在一個有效PE檔案中,但是你還是不能執行它,除非它被轉換成為受管原始代碼。這就是NGWS runtime 即時編譯器(也稱作JITters)大顯身手的時候。
為什麼你會對即時編譯代碼感到厭繁, 為什麼不把整個IL PE檔案編譯成原始代碼? 答案是時間——需要把IL代碼編譯成CPU規格的代碼的時間。這種編譯將更加有效率,因為一些程式段從來就沒有被執行過。例如,在我的文書處理器中,合併列印功能從來就沒有被編譯。
從技術上說,全部的處理過程如下:當一個類型被裝載時,裝載器建立一個存根(stub),並使它串連每一個類型的方法。當一個方法第一次被調用時,存根把控制交給JIT。JIT把IL編譯為原始代碼,且把存根指標指向緩衝了的原始代碼。接著的調用將執行原始碼。在某些位置上(At some point),所有的IL都被轉換成為原始代碼,而JITter處於空閑狀態。
正如我在前面提到的,JIT編譯器有很多,不止一個。在Windows平台上,NGWS runtime裝有3個不同的JIT編譯器。
JIT——這是NGWS runtime預設使用的JIT編譯器。它是一個後台(back end)最佳化的編譯器 ,在前台(up front)實行資料流分析,並建立了高度最佳化的受管原始代碼做為輸出結果。JIT可以使用不嚴格的IL指令集編碼,但是所需資源將十分可觀。主要的限制在於記憶體足跡(footprint)、結果工作集,以及實行最佳化所消耗的時間。
EconoJIT—— 和主JIT相比,EconJIT的目標是把IL高速地轉換成受管原始代碼。它允許緩衝所產生的原始代碼,但是輸出碼並不象主JIT產生的程式碼那樣最佳化(代碼小)。當記憶體緊張時,快速代碼產生方案的優勢將蕩然無存。通過永久地拋棄無用的已JIT過的代碼,你可以把更大的IL程式裝入代碼緩衝區。因為JIT編譯快,執行速度也仍然很快。
PreJIT—儘管它是基於主JIT的,但操作起來更象是一個傳 統的編譯器。你安裝了NGWS組件,它才能運行,才可以把IL代碼編譯成受管原始代碼。當然最終的結果為,更快的裝載時間和更快的應用程式啟動時間(不需要更多的JIT編譯)。
在所列出的JITters中,有兩個是運行時的JITters。可是你怎麼決定要使用哪一個JIT,它如何使用記憶體? 有一個稱做"JIT編譯管理器"的小應用程式(jitman.exe),它存放於NGWS SDK安裝目錄下的bin目錄中。當執行該程式時,它把一個表徵圖加到系統任務條上,雙擊該表徵圖開啟程式對話方塊(見圖2.1)。

圖2.1 JIT編譯管理器允許你設定各種相關效能的選項

儘管它是一個小小的對話方塊,可是你所選擇的選項功能是相當強大的。每一個選項將在以下描述。
Use EconoJIT only 選項——當該複選框沒有選上時,NGWS runtime使用預設的正常的JIT編譯器。前面就曾經解釋過兩種JITter的區別。
Max Code Pitch Overhead(%)選項——該設定僅保留給EconoJIT。它控制了JIT編譯時間和執行代碼時間的百分比。如果超過了設定的域值,代碼緩衝區得到擴充,以縮短JIT編譯所消耗的時間。
Limit Size of Code Cache選項——該項預設為非選。沒有選擇該項意味著緩衝區將使用它所能得到的記憶體。如果你想限制緩衝區大小,複選該選項,這將允許你使用Max Size of Cache(bytes)選項。
Max Size of Cache(bytes)選項—控制容納JIT代碼的緩衝區的最大值。雖然你可以非常嚴格地限制這個值,但你還是應該小心,不能超過這個緩衝區所適合的最大值。否則該方法的JIT編譯將會失敗。
Optimize For Size選項——告訴JIT 編譯器,最佳化的目的是為了使代碼更小而不是能執行得更快。這個設定預設是關掉的。
Enable Concurrent GC[garbage collection]選 項——垃圾收集(GC)預設地運行在使用者代碼的線程中。意味GC發生時,可能會注意到回應有輕微的延遲。為防止出現該現象,開啟當前GC。注意,當前GC比標準GC更慢,它僅在windows 2000上寫時(the time of writing)有效。
當用C#建立項目時,你可能使用不同的設定實驗過。當建立 UI-intensive應用程式時,你將會看到允許當前GC的最大差別。

2.2 虛擬對象系統(VOS)
到目前為止,你僅看到了NGWS runtime如何工作,但是並不瞭解它工作的技術背景以及為什麼它要這樣工作。這節都是關於 NGWS 虛擬對象系統的(VOS)。
以下為在VOS中形成聲明、使用和管理類型模型時,NGWS runtime的規則。在VOS背後的思想是建立一個架構,在執行代碼時不能犧牲效能,允許交叉語言整合和型別安全。
我提到的架構是運行時架構的基礎。為了協助你更好地瞭解它,我將它勾出四個地區。當開發C#應用程式和組件時,理解它們很重要。
VOS類型系統——提供豐富的類型系統,它打算支援全面程式設計語言的完全實施。
中繼資料——描述和引用VOS類型系統所定義的類型。中繼資料的永久格式與程式設計語言無關,但是,中繼資料拿自己當作一種互換機制(nterchange mechanism)來使用,這種互換是在在工具和NGWS的虛擬執行系統之間。
通用語言規範(CLS)——CLS定義了VOS中類型的子集,也定義了常規的用法。如果一個類庫遵守CLS的規則,它確保類庫可以在其它所有能實現CLS的程式設計語言上使用。
虛擬執行系統(VES)——這是VOS即時的實現。VES負責裝入和執行為NGWS運得時編寫的程式。
這四個部分一起組成了NGWS runtime架構。每一部分在下面小節中描述。

2.2.1 VOS類型系統
VOS類型系統提供豐富的類型系統,它打算支援多種程式設計語言的完全實施。所以,VOS必須都支援物件導向的語言和過程程式設計語言。
現在,存在著很多種近似但有點不相容的類型。就拿整型當例子,在VB中,它是16位長,而在C++中,它是32位。還有更多的例子,特別是用在日期和時間以及資料庫方面的資料類型。這種不相容使應用程式的建立和維護不必要地複雜化,尤其當程式使用了多種程式設計語言時。
另一個問題是,因為程式設計語言之間存在著一些差別,你不能在一種語言中重用另一種語言建立的類型。(COM用二進位標準介面部分地解決了這個問題)。 當今代碼重用肯定是有限的。
發布應用程式的最大障礙是各種程式設計語言的物件模型不統一。幾乎每一方面都存在著差異:事件、屬性、永久儲存(persistence)等等。
VOS這裡將改變 這種現象 。VOS定義了描述值的類型,並規定了類型的所有值所必須支援的一條合約。由於前面提到的支援物件導向和過程程式設計語言,就存在著兩種值和對象。

對於值,類型儲存於表述(representation)中,同樣操作也在其中實行。對象更強大因為它顯式地存於表述中。每一個對象都有一個區別於其它對象的識別號。支援不同的VOS類型在第四章 "C#類型"中提出。


2.2.2中繼資料
儘管中繼資料用於描述和引用由VOS類型系統定義的類型,但它還不能鎖定到這個單個目標。當你寫一個程式時,通過利用型別宣告,你所聲明的類型(假定它們是數實值型別或參考型別)被介紹給NGWS runtime類型系統。型別宣告在存於PE可執行檔內部的中繼資料中得到描述。
基本上,中繼資料用於各項任務:用於表示NGWS runtime用途的資訊,如定位和裝載類、 記憶體中這些類的案例、解決調用 、翻譯IL為原始碼、加強安全並設定運行時上下文邊界。
你不必關心中繼資料的產生。中繼資料是由C#的"代碼轉IL編譯器"(code-to-IL compiler,不是JIT編譯器)產生的。代碼轉IL編譯器發送二進位中繼資料資訊給PE檔案,是以標準的方式發送的,不象C++編譯器那樣,為出口函數建立它們自己的修飾名字。
你從中繼資料和可執行代碼並存所獲得的主要優勢為,有關類型的資訊同類型自身固定在一起,不會遍布很多地方。同樣有助於解決存在於COM中的版本問題。進一步地,你可以在相同的上下文中使用不同的版本庫,因為庫不僅被註冊表引用,也被包含在可執行代碼中的中繼資料引用。


2.2.3通用語言規範
通用語言規範(CLS)並不是虛擬對象系統(VOS)真正的一部分,它是特殊的。CLS定義了VOS中的一個類型子集,也定義了必須符合CLS的常規用法。
那麼,對此有什麼迷惑呢?如果一個類庫遵守CLS規則,其它程式設計語言同樣也遵守CLS規則,那麼其它程式設計語言的客戶也可以使用類庫。CLS是關於語言的互動可操作性(interoperability)。因此,常規用法必須僅遵循外部可訪問項目 (externally visible items)如方法、屬性和事件等等。
我所描述的優點是你可以做以下工作。用C#寫一個組件,在VB中派生它,因加在VB中的功能是如此之強大,在C#中再次從VB類派生它。只要所有的外部可訪問項遵守CLS規則,這樣是可行的。
我在這本書中出示的代碼不關心CLS協定。但在構建你的類庫時要注意到CLS協定。我提供了表2.1,用以給類型和外部可訪問項定義協定規則。
這個清單不完整。它僅包含一些很重要的項目。我不指出出現在本書中每一種類型的CLS協定,所以有個好主意:當你尋找CLS協定時,至少應該用瀏覽該表,以瞭解哪種功能有效。不要擔心你不熟悉這章表中的每一個含義,在這本書中你會學到它們。

表2.1 通能語言規範中的類型和功能

bool
char
byte
short
int
long
float
double
string
object(所有對象之母)

Arrays(數組)
數組的維數必須是已知的(>=1),而且最小下標數必須為0。
要素類型必須是一個CLS類型。

類型(Types)
可以被抽象或隱藏。
零或更多的介面可以被實現。不同的介面允許擁有具有相同名字和簽名的方法。
一個類型可以準確地從一個類型派生。允許成員被覆蓋和被隱藏。
可以有零或更多的成員,它們是欄位(fields)、方法、事件或者類型。
類型可以擁有零或更多個建構函式。
一種類型的可訪問性可以是公用的或者對NGWS組件來說是局部的;但是,僅公用成員可以認為是類型介面的一部分。
所有的值型必須從系統值型繼承。異常是一個枚舉——它必須從系統枚舉(System Enum)繼承。

類型成員
類型成員允許隱藏或者覆蓋另一種類型中的其它成員。
參數和傳回值的類型都必須是 CLS 協定 類型。
建構函式、方法和屬性可以被重載。
一個類型可以有抽象成員,但僅當類型不被封裝時。

方法
一種方法可以是靜態、虛擬或者執行個體。
虛擬和執行個體方法可以是抽象的,或者是一個實現。靜態方法必須總擁有一個實現。
虛擬方法可能是最後的(或者不是)。

欄位(Fields)
可以是靜態或者是非靜態。
靜態欄位可以被描述或只初始化。

屬性
當擷取和設定方法而不是使用屬性文法時,屬性可以公開。
擷取的傳回型別和設定方法的第一個參數必須是相同的CLS類型——屬性的類型。
屬性名稱字必須不同,不同的屬性類型用於區分是不充分的。
由於使用方法實現屬性訪問,如果 PropertyName 是同一個類中定義的一個屬性,你不能實現命名為 get_PropertyName 和 set_PropertyName 的方法。
屬性可以被索引。
屬性訪問必須遵循這種命名格式:get_ProName,set_PropName。

枚舉(Enumerations)
強調類型必須是byte、short、int 或long。
每一個成員是一個枚舉類型的靜態描述欄位。
一個枚舉不能實現任何介面。
你允許給多欄位設定相同的值。
一個枚舉必須繼承系統枚舉(隱含在C#中)

異常
可以被引發和被捕獲。
自訂異常必須繼承系統異常。

介面
可需要實現其它介面。
一個介面可以定義屬性、事件和虛擬方法。實現取決於衍生類別。

事件
增加和取消方法必須是都提供或者都沒有 ,每一種方法採用一個參數,它是一個從系統代表元(System Delegate)派生下來的類。

自訂屬性
可以僅使用下更類型:Type(類型),char, char, bool, byte, short, int, long, float, double, enum (一種CLS 類型), and object.

代表元(Delegates)
可以被建立和被啟用

標識符(Identifiers)
一個標識符的第一個字母必須來自一限制集。
通過大小寫在單一範圍內,不可能唯一地區別兩個或更多個標識符(大小寫不敏感)。

2.2.4虛擬執行系統(VES)
虛擬執行系統實現了虛擬對象系統。通過實現一個負責NGWS runtime的執行引擎(execution engine,縮寫EE)建立VES。這個執行引擎執行你用C#編寫和編譯的應用程式。
下列組件為VES的一部分。
1、中繼語言(IL)——被設計為很容易受各種各樣的編譯器所相容 。在該架構之外,C++、VB和C#編譯器都能夠產生IL。
2、裝入受管代碼——這包括解決記憶體中的名字、 表層類(laying out classes ),並且建立JIT編譯所必需的存根。通過執行經常性校正,包括加強一些訪問規則,類裝載器同樣也增強了安全性。
3、用JIT轉換IL成原始代碼——IL代碼並不是設計成為一種傳統的解釋位元組代碼或樹型代碼,IL轉換是真正的編譯。
4、裝入中繼資料、校正型別安全和方法的完整性
5、垃圾收集(GC)和異常處理——兩者都是基於堆棧格式的服務。受管代碼允許你動態地跟蹤堆棧。要動態地識別各個堆棧架構,JITter或其它編譯器必須提供一個代碼管理器。
6、描繪和查錯服務——兩者都取決於由源語言編譯器所產生的資訊。必鬚髮出兩個映射:一個映射從源語言結構發到指令流中的地址,一個映射從地址發到堆棧架構中的位置。當執行從IL到原始代碼的轉換時,這些映射被重新計算。
7、管理線程和上下文,還有遠端管理——VES為受管代碼提供這些服務。
雖然這個清單並不完整,但它足以讓你理解運行時基於的由VES提供的低層架構。肯定將會有專門討論運行時的書,而這本書將稍為深入地挖掘各種話題。

2.3 小結
這一章,我帶你逛了一回運行時的世界。我描述了當建立、編譯和配置C#程式時它是如何工作的。你學會了中繼語言(IL),還有中繼資料是如何用於描述被編譯為IL的類型。中繼資料和IL都用於JITter檢測和執行你的代碼。你甚至可以選擇用哪一種JITter來執行應用程式。
在這一章的第二部分,涉及到了運行時為何按這種方式工作的理論。你學了虛擬對象系統(VOS)和組成它的那部分。對於類庫設計者最為感興趣的就是通用語言規範(CLS),它為基於VOS的語言互動操作設定規則。最後,你看到了虛擬執行系統(VES)如何通過NGWS runtime實現VOS。


相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。