.NET 清理非託管資源

 

  • Dispose
     類型的 Dispose 方法應釋放它擁有的全部資源。它還應該經過調用其父類型的 Dispose 方法釋放其基類型擁有的全部資源。該父類型的 Dispose 方法應該釋放它擁有的全部資源並一樣也調用其父類型的 Dispose 方法,從而在整個基類型層次結構中傳播此模式。若要確保始終正確地清理資源,Dispose 方法應該能夠被屢次調用而不引起任何異常。Dispose 方法應該爲它處置的對象調用 GC.SuppressFinalize 方法。若是對象當前在終止隊列中,GC.SuppressFinalize 防止其 Finalize 方法被調用。請記住,執行 Finalize 方法會大大減損性能。若是您的 Dispose 方法已經完成了清理對象的工做,那麼垃圾回收器就沒必要再調用對象的 Finalize 方法。
    • 設計原則
     應用程序或類庫應只容許一個線程擁有資源的生存期,而且應在再也不須要資源時調用 Dispose。根據資源的不一樣,在處置資源時進行異步線程訪問可能會帶來安全風險。開發人員應仔細檢查本身的代碼,以肯定最佳的方法來強制線程安全。
    • 代碼示例
public class BaseResource: IDisposable
{
 
       
  // 非託管資源
   private IntPtr handle;
 
       
  // 託管資源
   private Component Components;
   // 對象是否已被釋放的標誌
   private bool disposed = false;

   public BaseResource()   {   }

   // 釋放資源,對外開放的可調用的方法
   public void Dispose()
   {
 
       
     // 釋放資源
      Dispose(true);
 
       
     // 指示在析構函數中跳過垃圾回收
      GC.SuppressFinalize(this);
   }

   // 釋放資源,若是disposing爲true,釋放全部的託管資源和非託管資源,若是爲false,則僅僅釋放非託管資源,這主要是爲了不在析構函數中重複2次進行垃圾回收
   protected virtual void Dispose(bool disposing)
   {
      // 檢查該對象是否已經被釋放了
      if(!this.disposed)
      {
         if(disposing)
         {
 
       
           // 釋放託管資源
            Components.Dispose();
         }
 
       
        // 釋放非託管資源
         CloseHandle(handle);
         handle = IntPtr.Zero;
      }
 
       
     // 標記該對象爲已被釋放的對象
 disposed = true; } // 析構函數,又名終結器 ~BaseResource() { // 釋放非託管資源,在調用終結器方法時系統自動會對託管的資源進行垃圾回收 Dispose(false); } // 容許屢次調用Dispose,但會拋出異常publicvoid DoSomething() { if(this.disposed) { thrownew ObjectDisposedException(); } } } 
    • 實現 Close 方法
     對於類型來講,若調用 Close 方法比調用 Dispose 方法更容易,則能夠向基類型添加一個公共 Close 方法。Close 方法又會調用沒有參數的 Dispose 方法,該方法能夠執行正確的清理操做。在基礎類庫中的全部類的Close方法都是基於該原理構造的。
public void Close()
{
   // 釋放資源
   Dispose();
}
  • Finalize(終結器)
     對於您的應用程序建立的大多數對象,能夠依靠 .NET Framework 的垃圾回收器隱式地執行全部必要的內存管理任務。可是,在您建立封裝非託管資源的對象時,當您在應用程序中使用完這些非託管資源以後,您必須顯式地釋放它們。
     雖然垃圾回收器能夠跟蹤封裝非託管資源的對象的生存期,但它不瞭解具體如何清理這些資源。對於這些類型的對象,.NET Framework 提供 Object.Finalize 方法,它容許對象在垃圾回收器回收該對象使用的內存時適當清理其非託管資源。可是對託管對象就不該該實現 Finalize方法,由於垃圾回收器會自動清理託管資源。
     默認狀況下,Finalize 方法不執行任何操做。若是您要讓垃圾回收器在回收對象的內存以前對對象執行清理操做,您必須在類中重寫 Finalize 方法。可是在 C# 或 C++ 編程語言中沒法重寫 Finalize 方法,因此在 C# 中可以使用析構函數語法實現 Finalize 方法。
     Finalize 方法主要是在未能調用 Dispose 方法的狀況下充當防禦措施來清理資源。
     實現 Finalize 方法或析構函數對性能可能會有負面影響,所以應避免沒必要要地使用它們。
     用 Finalize 方法回收對象使用的內存須要至少兩次垃圾回收。當垃圾回收器執行回收時,它只回收沒有終結器的不可訪問對象的內存。這時,它不能回收具備終結器的不可訪問對象。它改成將這些對象的項從終止隊列中移除並將它們放置在標爲準備終止的對象列表中。該列表中的項指向託管堆中準備被調用其終止代碼的對象。垃圾回收器爲此列表中的對象調用 Finalize 方法,而後,將這些項從列表中移除。後來的垃圾回收將肯定終止的對象確實是垃圾,由於標爲準備終止對象的列表中的項再也不指向它們。在後來的垃圾回收中,實際上回收了對象的內存。
  • 封裝資源對象
     若是您要編寫代碼,而該代碼使用一個封裝資源的對象,您應該確保在使用完該對象時調用該對象的 Dispose 方法。
    • 封裝方式
      • using語句
      • try/finally塊
相關文章
相關標籤/搜索