從今天開始讀CLR vir C#.雖然是英文版,但希望能從剛剛讀完的《你必須知道的.net》中找到共鳴。
本文簡單闡述從Source Code 到CPU Native Code 的執行期間,發生了什麼事?
把源碼編譯成Managed 程式碼
在.net環境下,我們可以採用多種語言來進行編程,比如C#,Vb.net,J#等。並且多種語言可以同時存在於同一專案中,這涉及到了CTS的內容,暫不闡述。每種語言都有其對應的編譯器存在,C#->CS Compiler,Vb.net->Basic Compiler等。如
不管什麼語言,通過各自的編譯器編譯後,都會產生PE檔案(Portable Executable file)也即託管模組(Managed Module).通常託管模組包括以下幾部分:
1.PE(32) Header
2.CLR Header (兩者描述一些附加資訊)
3.MetaData (主要包括兩個原資料表:一個描述源碼中的類型和成員資訊,一個面熟源碼引用到的類型和成員資訊)
4.IL(中間代碼:不管哪種程式設計語言(net支援的),都要編譯為統一的中間代碼)
注意:中繼資料在這裡是個很重要的角色,由於它的“自我描述”(由兩個原資料表決定了)簡單的來說,它可以:
1)造就了net的智能感知
2)允許對象的欄位被序列化與還原序列化(*)
3)使得GC可以追蹤到對象的參考關聯性,得到對象的生命週期
4)保證了編寫安全的代碼(*)
託管模組產生Assembly
到達中間代碼,接下來好像就輪到CLR 的JIT編譯機制,在運行時把其編譯成本地代碼即可。實際上,CLR是不與managed module發生作用的,managed module要首先由對應的編譯器編譯成Assembly(DLL, exe)後,CLR與Assembly互動。見:
根據我們平時的編程經驗來理解上述Assembly產生:比如一個winform專案,裡麵包括form ,images等資源,編譯時間,可以選擇產生類庫(DLL),或者可執行檔(EXE),這個時候,就會把所有的資源(源碼,images)等全部“打包”成一個DLL/Exe,如果是建立類庫的專案則更加如此。
當然,產生的Assembly(DLL/Exe)要想在用戶端運行,需要CLR的支援,這也就是為什麼我們在部署的winform專案的時候,在client端安裝framework的原因了。
JIT執行Assembly
從上面的描述中可以知道,產生的Assembly是在運行時由JIT進行編譯執行的,而這個過程正式託管程式效能的一個很到的體現:
如下代碼:
Code
static void Main()
{
Console.WriteLine("Hello");
Console.WriteLine("World");
}
當第一次調用WriteLine方法時,
1.JIT Compiler從中繼資料中找到要調用的方法,
2.從而找到方法在IL中的位置,這個動作可以從上面對中繼資料的描述中得到得以解釋。
3.分配空間
4.JIT把IL編譯成本地代碼
(註:這個過程中實際上還有一個動作:Verification(驗證),此驗證用來保證代碼的安全性。比如驗證方法參數是否一致,傳回值是否正常返回等。)
5.把產生的本地代碼儲存在動態產生的記憶體空間中
6.運行指標跳轉至本地代碼執行
這個過程簡單的闡述了運行時的JIT工作流程。
當第二次調用WriteLine方法時,由於在本地記憶體中已經儲存有此方法的本地代碼,所以JIT的編譯過程將被繞過,直接執行本地代碼,從而使執行效能得到提高。
從這個角度看,我們平時講的封裝和複用等思想,在代碼最佳化,效能提高方法都會起到很好的作用。
當然,如果應用程式關閉,動態記憶體得以釋放,產生的本地代碼也就不存在了。
CTS一般型別系統
上文中提到,net實現了多語言的互操作,這個特性需要CTS和CLS的支援。
CTS中定義類型中能夠定義什麼,如何定義等規範,並對類型的存取層級做了規範(private,famlily,public等),可以看到,裡面的定義如family實際上對應的IL中的定義,具體的每種語言中都有自己的映射定義,如protected.
又比如對資料類型的定義,CTS中的Int32,在C#中可以為int即可。這些只是
一些映射定義,編譯為IL後,實際還是要稱為CTS中定義的類型Int32.
這種特性,就使得開發人員可以用自己熟悉的語言,自己熟悉的文法進行編程,完成後還可以進行與其他語言代碼的互動。
而相反,沒有在CTS中定義的規範,在具體的語言中是停用:比如C++語言支援多繼承,而在CTS中定義對於類只是是單向單繼承,所以net環境下寫C++代碼就必須符合這個規範,寫多繼承的代碼會出現編譯錯誤。
CLS通用文法規範
如果說CTS定義了統一的編程規範,那麼CLS就定義了實現語言互操作每種語言必須符合的最小集合。
如果要實現互操作的編碼,可以使用[assembly:CLSCompliant(true)] 特性,來檢查代碼是否符合CLS規範。
Code
using System;
using System.Runtime.InteropServices;
[assembly:CLSCompliant(true)]
namespace Demo1
{
public class cls
{
static void Main(string[] args)
{
}
public UInt32 foo()
{
UInt32 i = 10;
return i;
}
}
}
由於在VB.net中不存在Uint32的定義,所以foo方法會得到警告:不符合CLS規範。
具體的規範內容,需要參考相關文檔得知。