C#託管代碼、非託管代碼及回收機制

網上找了下相關文字,發現一些很不錯的,轉過來,方便之後查看程序員

託管代碼

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

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

非託管代碼

  非託管代碼就是在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++中,你有另外一個選擇。即便你正建立一個託管程序,你能夠決定哪些類是託管類型,哪些類是非託管類型的。服務器

非託管類型:app

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來建立,永遠都不會在棧中出現。因此下面這行代碼是合法的:spa

Foo f;//非託管類型

可是這一行代碼就是非法的:

Bar b;//託管類型必須用new來建立

若是我在堆中建立一個Foo對象,那麼我必需要負責清理這個對象:

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

  C++編譯器實際上會用兩個堆,一個託管堆和一個非託管堆,而後經過對new操做符的重載來實現對建立不一樣類型類的實例,分配不一樣的內存。若是我在堆裏面建立一個Bar實例,那麼我能夠忽略它。當沒有其餘代碼在使用它的時候,垃圾回收器會自動清理這個類,釋放其佔用的資源。對於託管類型會有一些約束:它們不能實現多重繼承,或者繼承與非託管類型;它們不能用friend關鍵字來實現私有訪問,它們不能實現拷貝構造函數。因此,你有可能不想把你的類聲明爲託管類型。可是這並不意味着你不想讓你的代碼成爲託管代碼。在Visual C++中,你能夠選擇。

託管代碼的執行過程

  選擇編譯器:爲得到公共語言運行庫提供的優勢,必須使用一個或多個針對運行庫的語言編譯器,如 Visual Basic、C#、Visual C++、JScript 或許多第三方編譯器(如 Eiffel、Perl 或 COBOL 編譯器)中的某一個。因爲運行庫是一個多語言執行環境,所以它支持各類數據類型和語言功能。您所用的語言編譯器首先肯定可用的運行庫功能,而後使用這些功能設計代碼。編譯器(而不是運行庫)創建代碼必須使用的語法。若是您的組件必須徹底可以被用其餘語言編寫的組件使用,您的組件的導出類型必須只公開公共語言規範 (CLS) 中包括的語言功能。

  編譯,將源代碼翻譯爲microsoft中間語言(MSIL)並生成所需的元數據。

  在執行時,實時 (JIT) 編譯器將 MSIL 翻譯爲本機代碼。在此編譯過程當中,代碼必須經過驗證過程,該過程檢查 MSIL 和元數據以查看是否能夠將代碼肯定爲類型安全。

  運行代碼:公共語言運行庫提供使執行可以發生以及可在執行期間使用的各類服務的結構。

c# -- 對象銷燬和垃圾回收

  有些對象須要顯示地銷燬代碼來釋放資源,好比打開的文件資源,鎖,操做系統句柄和非託管對象。在.NET中,這就是所謂的對象銷燬,它經過IDisposal接口來實現。再也不使用的對象所佔用的內存管理,必須在某個時候回收;這個被稱爲無用單元收集的功能由CLR執行。

  對象銷燬和垃圾回收的區別在於:對象銷燬一般是明確的策動;而垃圾回收徹底是自動地。換句話說,程序員負責釋放文件句柄,鎖,以及操做系統資源;而CLR負責釋放內存。

  C#處理銷燬的一個備選方案--Finalizer及其模式。

相關文章
相關標籤/搜索