1. 程式人生 > >.NET 託管程式碼和非託管程式碼的區別

.NET 託管程式碼和非託管程式碼的區別

什麼是託管程式碼(managed code)?

託管程式碼是一microsoft的中間語言(IL),他主要的作用是在.NET FRAMEWORK的公共語言執行庫(CLR)執行程式碼前去編譯原始碼,也就是說託管程式碼充當著翻譯的作用,原始碼在執行時分為兩個階段:

1.原始碼編譯為託管程式碼,(所以原始碼可以有很多種,如VB,C#,J#)
2.託管程式碼編譯為microsoft的平臺專用語言。

編譯器把程式碼編譯成中間語言(IL),而不是能直接在你的電腦上執行的機器碼。中間語言被封裝在一個叫程式集(assembly)的檔案中,程式集中包含 了描述你所建立的類,方法和屬性(例如安全需求)的所有元資料。你可以拷貝這個程式集到另一臺伺服器上部署它。

託管程式碼在公共語言執行庫(CLR)中執行。這個執行庫給你的執行程式碼提供各種各樣的服務,通常來說,他會載入和驗證程式集,以此來保證中間語言的正確 性。當某些方法被呼叫的時候,執行庫把具體的方法編譯成適合本地計算機執行的機械碼,然後會把編譯好的機械碼快取起來,以備下次呼叫。(這就是即時編譯) 隨著程式集的執行,執行庫會持續地提供各種服務,例如自動垃圾回收、執行庫型別檢查和安全支援等。這些服務幫助提供獨立於平臺和語言的、統一的託管程式碼應 用程式行為。

Visual Basic .NET和C#只能產生託管程式碼。如果你用這類語言寫程式,那麼所產生的程式碼就是託管程式碼。如果你願意,Visual C++ .NET可以生成託管程式碼。當你建立一個專案的時候,選擇名字是以.Managed開頭的專案型別。例如.Managed C++ application。

什麼是非託管程式碼(unmanaged code)?

非託管程式碼就是在Visual Studio .NET 2002釋出之前所建立的程式碼。例如Visual Basic 6, Visual C++ 6, 最糟糕的是,連那些依然殘存在你的硬碟中、擁有超過15年曆史的陳舊C編譯器所產生的程式碼都是非託管程式碼。託管程式碼直接編譯成目標計算機的機械碼,這些代 碼只能執行在編譯出它們的計算機上,或者是其它相同處理器或者幾乎一樣處理器的計算機上。非託管程式碼不能享受一些執行庫所提供的服務,例如安全和記憶體管理 等。如果非託管程式碼需要進行記憶體管理等服務,就必須顯式地呼叫作業系統的介面,通常來說,它們會呼叫Windows SDK所提供的API來實現。就最近的情況來看,非託管程式會通過COM介面來獲取作業系統服務。

跟Visual Studio平臺的其他程式語言不一樣,Visual C++可以建立非託管程式。當你建立一個專案,並且選擇名字以M FC,ATL或者Win32開頭的專案型別,那麼這個專案所產生的就是非託管程式。

區別:

1、託管程式碼是一種中間語言,執行在CLR上;

非託管程式碼被編譯為機器碼,執行在機器上。

2、託管程式碼獨立於平臺和語言,能更好的實現不同語言平臺之間的相容;

非託管程式碼依賴於平臺和語言。

3、託管程式碼可享受CLR提供的服務(如安全檢測、垃圾回收等),不需要自己完成這些操作;

非託管程式碼需要自己提供安全檢測、垃圾回收等操作。

託管程式碼就意味著託管資料?答案是否定的。

對於Visual Basic和C#來說,生活是簡單的,因為你沒有其它選擇。當你在那些語言裡面宣告一個類,那麼這個類的例項會在託管堆中被建立,垃圾收集器(GC)會幫 我們管理這些物件的回收。但是在Visual C++中,你有另一個選擇。即使你正建立一個託管程式,你可以決定哪些類是託管型別,哪些類是非託管型別的。

這就是非託管型別:

class Foo {    private:       int x;    public:       Foo(): x(0){}       Foo(int xx): x(xx) {} };

這就是託管型別

__gc class Bar {    private:       int x;    public:       Bar(): x(0){}       Bar(int xx): x(xx) {} };

他們唯一的區別就是類Bar的定義中有__gc關鍵字。這個關鍵字會給程式碼帶來巨大的區別。

託管型別是可以被垃圾回收器所回收的。他們必須要用關鍵字new來建立,永遠都不會在棧中出現。所以下面這行程式碼是合法的:

Foo f;

但是這一行程式碼就是非法的:

Bar b;

如果我在堆中建立一個Foo物件,那麼我必須要負責清理這個物件:

Foo* pf = new Foo(2);       // . . .       delete pf;

C++編譯器實際上會用兩個堆,一個託管堆和一個非託管堆,然後通過對new操作符的過載來實現對建立不同型別類的例項,分配不同的記憶體。如果我在堆裡面 建立一個Bar例項,那麼我可以忽略它。當沒有其他程式碼在使用它的時候,垃圾回收器會自動清理這個類,釋放其佔用的資源。 對於託管型別會有一些約束:它們不能實現多重繼承,或者繼承於非託管型別;它們不能用friend關鍵字來實現私有訪問,它們不能實現拷貝建構函式。所 以,你有可能不想把你的類宣告為託管型別。但是這並不意味著你不想讓你的程式碼成為託管程式碼。在Visual C++中,你可以選擇。

託管程式碼與非託管程式碼的效能比較

基本上每個人都知道的是,所有.Net語言都將被編譯成為一個叫做IL彙編的中間語言。但是計算機是如何執行這個中間程式碼的,卻是很多人不知道,甚至理解 錯誤了的。

JIT是.NET程式執行的重要部件之一,全稱是即時編譯器。很多人(絕對不是少數,問了很多c++程式設計師,10個有9個這種想法)都以為JIT其實就是 跟Java VM差不多的東西,是一個Interpreter,在執行時讀取IL彙編程式碼,然後模擬成x86程式碼(也就是俗稱的虛擬機器)。但是事實上,.NET使用的 是更為高階的技術。 .Net程式被載入入記憶體以後,當某段IL程式碼被第一次執行的時候,JIT編譯器就會將這段IL程式碼,全部編譯成原生代碼,然後再執行。這也就是為什 麼.NET程式第一次執行都啟動很慢的原因! 隨.NET庫,微軟還附帶了一個工具,可以事先將.NET程式所有的IL程式碼都編譯成原生代碼並儲存在快取區中,這樣一來,這個程式就跟c++編譯的一模 一樣了,沒有任何區別,執行時也可以脫離JIT了(這裡不要混淆了,這裡不是說可以脫離.NET庫,而是說不需要在進行即時編譯這個過程了)。所以,請不 要將.NET和Java混為一談,兩個的執行效率根本不是一個等級的!

JIT的優化指的是可以針對本地CPU,在編譯時進行優化。傳統程式在編譯時,為了保證相容性,通常使用最通用的指令集(比如古老的386指令集)來編譯。而JIT知道CPU的具體型別,可以充分利用這些附加指令集進行編譯,這樣的效能提升是很可觀的。