.NET 代碼編譯過程


作為一種代碼指令平台,Microsoft .NET比微軟公司先前推出的其他技術平台要來得更為復雜。由於.NET提供了對多種編程語言以及(在理論上說)多重平台的支持,這就需要在傳統的兩個代 碼層添加一個中間代碼層。在這里,傳統的兩層分別是源代碼層和編譯后的本機代碼層。新加的代碼層給.NET平台帶來了額外的靈活性,不過,反過來卻又增加 了系統的復雜性。此外,由於這一新代碼層的出現,一連串的新型應用程序部署選項也首次展現在了程序員的面前。

.NET之與眾不同:MSIL       

在Microsoft .NET框架內,應用程序可以用好多種高級程序語言編寫、創建,例如VB.NET、C#乃至COBOL .NET等等都可以編寫.NET應用程序。而通過每一種遵守.NET規范的編程語言所編寫的程序代碼首先都得通過一種初始編譯步驟從源代碼變成.NET的 公共標准語言:MSIL(微軟中介語言:Microsoft Intermediate Language)。MSIL自身是一種完整的、和對象相關的語言,只有它才可能創建出應用程序。為了大致了解MSIL的一些有關情況,你可以參看“通過 MSIL語言了解CLR的運行原理”一文。.NET應用程序是以MSIL的形式出現的,只有在程序執行的時候才通過即時編譯器(JIT)被編譯為本機代 碼。

.NET的編譯過程:從源代碼到本機指令

        只要裝載了assembly代碼就會進行JIT編譯,可見這是一種匯編級的編譯(了解更多assembly技術的細節請參看“Assembly—治愈 “DLL地獄”的良方?”一文)。在編譯過程中,JIT編譯器一旦首次遭遇對象的索引就會裝載匹配對象各個方法聲明的對應程序。這樣,以后調用方法的時候 就會編譯其IL,而方法的對應根程序則被方法的編譯后代碼的地址所取代。這一過程在每次方法被首次調用的時候進行,產生的本機代碼則被緩沖以便會話過程中 下次裝載assembly代碼的時候可以被使用。顯然,這樣的指令系統相比傳統的編譯語言需要更大的處理能力,不過其要求也沒有你想象的那么高。

    在這里必須澄清一個普遍誤解的錯誤概念,那就是不少人認為.NET應用程序是解釋型而非編譯型的程序。另外,還有這樣的常見錯誤認識:JIT編譯的代碼存 儲在磁盤上並且可以為同一應用程序執行。雖然這樣做也不是不可以,但是,你很快就會明白,這可不是缺省的編譯方案。應用程序的IL代碼實際上在每次應用程 序運行的時候都會被重新編譯為本機代碼。

兩種編譯器

    事實上,JIT編譯器分成兩種(經濟編譯器和普通編譯器),而且它們生來也不是平等的。經濟JIT編譯器代表了運行一個.NET應用程序所需要的最少功 能,它直接用對等的本機代碼取代每一條MSIL指令,不進行任何優化從而也帶來更少的系統負載。這也意味着它主要應用在內存等資源比較緊張的平台上。

    另一方面,普通JIT編譯器則是缺省的運行時配置,它會對其產生的代碼進行即時優化。這樣做無形中給予了.NET超出傳統預編譯語言的一個優點:預編譯語 言只能對其處理的代碼將要運行於其上的平台做一番大致的事前估計。JIT編譯器可以經過准確調節達到當前運行時狀態,結果可以完成一些預編譯語言無法完成 的工作:

·更高效地利用和分配CPU寄存器
·在適當的情況下實施低級代碼優化,比如常量重疊、拷貝復制、取消范圍檢查、取消常規副表達式以及方法內聯等
·在代碼執行期間監控當前的物理和虛擬內存需求從而更高效地利用內存
·產生特定的平台指令以准確、充分地利用實際的處理器模式

        .NET編譯的結果就是JIT所帶來的額外負載要求並沒有產生顯著的性能損失。

性能選項

        這就是說,每次運行應用程序時MSIL就會被JIT編譯。記住,這就是常識了,然后,根據以上內容中說明的原理,在開始啟動應用程序以及首次使用非核心功能的時候顯然會導致低於優化級的系統性能表現。那么你又該采取什么措施把這種負面影響降低到最小呢?

        微軟公司的對策是為我們提供了一種名為Pre-JIT的編譯器(也被稱做本機映像生成器:Native Image Generator,程序名因此是Ngen.exe)。從表面上看,至少它也算是應付任何性能問題的一項治療手段。Pre-JIT編譯器在運行時之前被調 用,在安裝時,它會把全部assembly形式的MSIL編譯為本機代碼。這種本機代碼隨后存儲在全局assembly緩存(Global Assembly Cache)的某一個特殊部分供以后使用,這樣就完全繞過了JIT編譯過程。

        乍看之下,這樣做應該是解決先前的問題了,對客戶端代碼而言尤其如此。但是,你還記得嗎?普通JIT在編譯MSIL的時候實施了大量的即時優化操作。而許 多此類的優化操作,尤其是那些牽扯到寄存器和存儲器使用的優化,都是由系統的當前需求所驅動的。所以,批量編譯assembly代碼的舉措就會阻止這些優 化的進行從而在實際上產生出運行更慢的最終代碼。在你采用這個法子之前,微軟的建議是,比照普通編譯下的當前條件,把你的JIT和Ngen版本設置為目標 平台上的同一匯編級。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM