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# - 資源釋放的觀念整理 < 這篇寫的真的不錯,此筆記由此文整理
沒有留言:
張貼留言