.net 編譯原理

這聽起來像是個很是高大上的名字,上學的時候咱們學過的編譯原理或者編譯技術其實是在講如何將高級程序語言如C++編譯爲計算機能夠理解的彙編語言,這裏說的編譯原理只是想說明在.NET的世界裏編譯這件事兒和傳統的C++有什麼區別和聯繫。先來簡單的說一下傳統的作法,在C++裏,但你編譯一個應用程序好比一個EXE文件或者是DLL(注意這裏的DLL叫作動態連接庫,只是到了.NET中才才被叫作程序集)時,實際上編譯器作的事情就是直接將你寫的C++代碼編譯爲彙編語言,而後以二進制的形式存放在EXE或者DLL文件中,當被執行的時候,CPU就能夠直接讀到彙編代碼開始運行了。固然提及來簡單,裏面仍是有很是多的細節問題,咱們須要關注的重點是,C++編譯器作到的事情是將高級語言直接編譯爲彙編語言html

 

接下來,咱們來看一看在.NET中咱們如何處理。在說明以前,咱們來回顧一下一個很是經典的說法,你看任何一本介紹.NET的書都會在開篇宣稱.NET是跨平臺跨語言的高級運行時,可是.NET是如何作到的呢?咱們引入一個很是關鍵的概念叫作Intermediate Language簡稱IL,中文叫作中間語言。linux

 

當你寫了一段程序(假設是一個Console Application EXE的項目),在Visual Studio中點擊F5編譯並運行這個按鈕的時候,實際上都發生了些什麼呢?程序員

  1. 首先是編譯,與C++相似,.NET編譯器也是將高級語言編譯,可是輸出並非彙編語言,而是IL中間語言。這個所謂的IL是個什麼東西呢?你能夠理解爲,這是和C#相似的一種語言,程序員能夠很容易的看懂甚至直接用Visual Studio就能夠寫。而後這些中間語言會以二進制的形式存放在EXE文件中。
  2. 接下來是運行。運行的時候.NET Runtime會加載EXE中的必要信息以及IL,這時你可能會問,C++運行的時候,CPU能夠直接運行彙編,可是CPU能認識IL麼?答案是否認的,CPU會IL一無所知。.NET運行時會進行二次編譯,將IL編譯爲真正的彙編語言,而後CPU執行。

注意,.NET的程序要運行,其實是須要兩次編譯的,一次是在開發的時候,另一次則是在運行的時候。那麼這樣作實際上解決了.NET跨語言跨平臺這個問題。.面試

 

NET上會不少種語言,好比C#,VB.NET, C++.NET, F#,這些語言開發出來的程序,只要機器上裝了.NET Framework就均可以運行,這是由於不一樣的語言在第一次(開發過程)編譯的時候都會被編譯爲IL,也就是說,一樣的一個功能,用C#寫出來和F#寫出來編譯出來的IL是同樣的(固然編譯器可能根據不一樣的高級語言特色有所優化,可是基本一致)。這樣作的好處是什麼呢?很簡單,好比你用C#寫了一個feature,我用F#加載你的DLL就可使用你的程序集了。這看起來沒什麼,可是你能想一想一下若是C++能夠很是簡單的調用Java的類庫,這個世界是否是就該瘋狂了?再來是跨平臺,當你的.NET程序運行的時候,.NET運行時負責將IL編譯爲彙編語言,在運行編譯時,.NET能夠根據當前運行的操做系統以及CPU構架的不一樣生成徹底不同的彙編語言。可是C++就作不到,你用一種編譯器編譯出來的東西只能運行在某個特定的平臺上,好比VC編譯器編譯出來的只能跑在windows上,在linux上就完蛋了。這是.NET很是重要的一個框架技術核心,雖然如今被應用的並不普遍,由於除了C#和Windows平臺意外,.NET是不多被使用的。可是若是將來微軟將.NET技術推廣到更多領域,這種跨平臺跨語言的框架核心就能顯示出價值了。看一下下面這個圖。windows

 

[.NET <wbr>Framework] <wbr>編譯原理

接下來咱們來看幾個很是重要的相關的面試問題緩存

 

首先,二次編譯帶來的性能損失。這很容易理解,與C++相比,運行.NET程序在運行的時候多了一次編譯,這確定是要慢的。.NET runtime作了一些性能的優化,即由IL編譯過的彙編語言會被緩存起來,當第二次再遇到一樣的IL的時候,會直接從內存中加載,而再也不被編譯。這也就是.NET程序會被指責第一次運行極慢無比的一個重要緣由。好比咱們來看看下面這段code...框架

 

Console.WriteLine("Hello world"); // first time, compile this function性能

Console.WriteLine("Hello world again"); // second time, load from cache優化

 

固然爲了提升性能,.NET編譯器容許將高級語言如C#直接編譯爲彙編語言,可是並不推薦這樣作,這樣的會,全部跨平臺,跨語言的特性就將消失,這種作法適用於對性能要求極高的應用程序。this

 

第二,反編譯的故事。全部.NET的DLL都是中間語言組成的,因此,你能夠用反編譯器加載DLL,由中間語言反編譯爲C#以此看到其餘程序集的源代碼。固然.NET提供了加密保護機制,當你編譯爲DLL的時候能夠加入擾碼,使反編譯器沒法理解IL。

 

第三,這是反射的基礎。你確定知道反射的故事,在運行時能夠動態的加載某個類型中全部的property, field等等,.NET就是經過分析中間語言作到這一點的。在運行時,.NET runtime會加載IL並理解全部的類型定義。

 

 好了,這就是全部.NET編譯的基本故事了,雖說和你寫code沒什麼太大關係吧,做爲.NET的核心技術框架,這個仍是要了解一下的。That's much for today. [.NET <wbr>Framework] <wbr>編譯原理

相關文章
相關標籤/搜索