2016年4月18日 星期一

[C#] 資源釋放的觀念整理 - 筆記


C# 資源釋放的觀念整理 - 筆記
  • 變數分為數值型別參考型別
    • 前者配置於stack, 後者配置於heap
    • 前者當離開變數有效範圍就會直接被釋放
    • 後者僅被視為garbage, 等待GC回收, 不馬上回收視基於調整heap效率所設計的最佳策略
    • 後者發生時: 比如變數assign成NULL、重新指向其他物件、重新初始化
  • 以上資源皆由CLR配置並管理
  • CLR控制的資源稱為manage資源,其他稱unmanage 資源
    • manage資源會自動被GC回收 不須操心
    • unmanage資源必須定義在釋放函式(自行定義如何釋放)
  • 而C#的 Finalize()類似destructor,但是並非明確的在離開有效範圍就被呼叫,而是等待GC呼叫
    • 因此當programmer需要明確定義哪邊要釋放資源時,就會透過設計Dispose()函數來供programmer呼叫
    • 而Dispose發生在: 1. 被programmer明確呼叫的地方    2. Using {...}區塊結束時
      • 而Dispose函數釋放的資源分為兩個部分, 1是manage部分, 2是unmanage的部分
        • Programmer呼叫Dispose()函數視同宣告此變數已無效
        • Programmer呼叫Dispose(): 會呼叫protected型態的Dispose(true)釋放所有資源
        • 倘若是由Finalize()呼叫Dispose,是已離開變數有效範圍的位置,那就只需要回收unmanage資源,因此只需呼叫Dispose(false)的部分
      • 注意,
        倘若Dispose被成功執行了,為了避免稍後Finalize()又再度呼叫一次(註1)Dispose(),Dispose通常還會加上一行 GC.SuppressFinalize(this),告知GC不須在呼叫Dispose()
      • 註1: (http://readily-notes.blogspot.tw/2013/11/gcsuppressfinalize.html)
      • 具有解構子的物件其在被垃圾收集器回收處理時,會先被放入解構佇列之中,再交由另一個專門處理解構動作的執行緒去做解構的動作,當解構的動作完成,該物件又會被放回原來的佇列等待垃圾收集器的回收,因此其性能上的耗費會比沒有解構子的物件還來的多。由於IDisposable在實作上會習慣加入解構子做為保險措施,防止類別的使用者忘記叫用Dispose方法,造成資源的洩漏。故在釋放完資源後,我們應該隨即在後呼叫GC.SuppressFinalize,告知垃圾收集器該物件的解構動作跳過不處理。 
以上是資源釋放的概念,最後附上MSDN的範例code與供我悟懂的原文

// Design pattern for a base class.
public class Base: IDisposable
{
   //Implement IDisposable.
   public void Dispose() 
   {
     Dispose(true);
      GC.SuppressFinalize(this); 
   }

   protected virtual void Dispose(bool disposing) 
   {
      if (disposing) 
      {
         // Free other state (managed objects).
      }
      // Free your own state (unmanaged objects).
      // Set large fields to null.
   }

   // Use C# destructor syntax for finalization code.
   ~Base()
   {
      // Simply call Dispose(false).
      Dispose (false);
   }
}
C# - 資源釋放的觀念整理 < 這篇寫的真的不錯,此筆記由此文整理

沒有留言:

張貼留言