.net 中的托管與非托管


參考文獻

關於托管與非托管

到底什么是托管,什么是非托管的研究

前言

最近在看《ASP.NET MVC 4框架揭秘》,里面有很多微軟.net的東西,其中就很多次提到了托管與非托管,搞得我雲里霧里的,今天特地抽空來整理一下。大部分內容都是參考別人的。

托管代碼

托管代碼就是Visual Basic .NET和C#編譯器編譯出來的代碼。編譯器把代碼編譯成中間語言(IL),而不是能直接在你的電腦上運行的機器碼。中間語言被封裝在一個叫程序集(assembly)的文件中,程序集中包含了描述你所創建的類,方法和屬性(例如安全需求)的所有元數據。你可以拷貝這個程序集到另一台服務器上部署它。通常來說,這個拷貝的動作就是部署流程中唯一的一個操作。

托管代碼公共語言運行庫(CLR)中運行。這個運行庫給你的運行代碼提供各種各樣的服務,通常來說,他會加載和驗證程序集,以此來保證中間語言的正確性。當某些方法被調用的時候,運行庫把具體的方法編譯成適合本地計算機運行的機械碼,然后會把編譯好的機械碼緩存起來,以備下次調用(這就是即時編譯)隨着程序集的運行,運行庫會持續地提供各種服務,例如安全,內存管理,線程管理等等。這個程序被“托管”在運行庫中。Visual Basic .NET和C#只能產生托管代碼。如果你用這類語言寫程序,那么所產生的代碼就是托管代碼。如果你願意,Visual C++ .NET可以生成托管代碼。當你創建一個項目的時候,選擇名字是以.Managed開頭的項目類型。例如.Managed C++ application。

非托管代碼

非托管代碼就是在Visual Studio .NET 2002發布之前所創建的代碼,例如Visual Basic 6, Visual C++ 6。 最糟糕的是,連那些依然殘存在你的硬盤中、擁有超過15年歷史的陳舊C編譯器所產生的代碼都是非托管代碼。非托管代碼直接編譯成目標計算機的機械碼這些代碼只能運行在編譯出它們的計算機上,或者是其它相同處理器或者幾乎一樣處理器的計算機上。非托管代碼不能享受一些運行庫所提供的服務,例如安全和內存管理等。如果非托管代碼需要進行內存管理等服務,就必須顯式地調用操作系統的接口,通常來說,它們會調用Windows SDK所提供的API來實現。就最近的情況來看,非托管程序會通過COM接口來獲取操作系統服務。跟Visual Studio平台的其他編程語言不一樣,Visual C++可以創建非托管程序。當你創建一個項目,並且選擇名字以MFC,ATL或者Win32開頭的項目類型,那么這個項目所產生的就是非托管程序。

總而言之,非托管代碼是運行在公共語言運行庫環境(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;//托管類型必須用new來創建

如果我在堆中創建一個Foo對象,那么我必須要負責清理這個對象:

Foo* pf = new Foo(2);
// . . .
delete pf;//手動清理

C++編譯器實際上會用兩個堆,一個托管堆和一個非托管堆,然后通過對new操作符的重載來實現對創建不同類型類的實例,分配不同的內存。如果我在堆里面創建一個Bar實例,那么我可以忽略它。當沒有其他代碼在使用它的時候,垃圾回收器會自動清理這個類,釋放其占用的資源。對於托管類型會有一些約束:它們不能實現多重繼承,或者繼承與非托管類型;它們不能用friend關鍵字來實現私有訪問,它們不能實現拷貝構造函數。所以,你有可能不想把你的類聲明為托管類型。但是這並不意味着你不想讓你的代碼成為托管代碼。在Visual C++中,你可以選擇。

托管代碼的執行過程

  1. 選擇編譯器:為獲得公共語言運行庫提供的優點,必須使用一個或多個針對運行庫的語言編譯器,如 Visual Basic、C#、Visual C++、JScript 或許多第三方編譯器(如 Eiffel、Perl 或 COBOL 編譯器)中的某一個。由於運行庫是一個多語言執行環境,因此它支持各種數據類型和語言功能。您所用的語言編譯器首先確定可用的運行庫功能,然后使用這些功能設計代碼。編譯器(而不是運行庫)建立代碼必須使用的語法。如果您的組件必須完全能夠被用其他語言編寫的組件使用,您的組件的導出類型必須只公開公共語言規范 (CLS) 中包括的語言功能。
  2. 編譯,將源代碼翻譯為microsoft中間語言(MSIL)並生成所需的元數據。
  3. 在執行時,實時 (JIT) 編譯器將 MSIL 翻譯為本機代碼。在此編譯過程中,代碼必須通過驗證過程,該過程檢查 MSIL 和元數據以查看是否可以將代碼確定為類型安全。
  4. 運行代碼:公共語言運行庫提供使執行能夠發生以及可在執行期間使用的各種服務的結構。

 

 

 


免責聲明!

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



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