C#Dispose模式
- 目的:
為了及時釋放寶貴的非托管資源和托管資源,並且保證資源在被gc回收的時候可以正確釋放資源,同時兼顧執行效率
- 必須遵循的事實:
1 托管資源釋放:
由另一線程的gc進行釋放,當托管的對象沒有被引用時,就會在“適當的時候”進行回收
如果定義了析構函數,回收的時候會調用析構函數(實際執行可能有差別),之后釋放對象占用的內存。
當類有析構函數時, gc會分分兩步來釋放,如果沒有析構函數或者指定不需要調用析構函數時,只需要一步就能釋放
2 非托管資源必須顯式釋放
- 方案:
1.把資源釋放都放在析構函數里。
可以保證資源都釋放,但是由於gc調用時機的不確定性,導致寶貴的非托管資源無法及時釋放。
2. 寫個釋放函數,手動是調用
如果忘了釋放的話, 托管資源會被gc釋放,但非托管資源就無法釋放
3. Dispose模式。參考下面的代碼
手動調用Dispose() 可以釋放所有資源,並且在gc標記不需要再調用析構函數,從而提高了效率。
如果忘記調用Dispose(), 則當gc調用析構函數的時候也會把非托管資源釋放掉
-------參考代碼-----------
public interface IDisposable { void Dispose(); } public class DisposablClass : IDisposable { //是否回收完畢 bool _disposed; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); //標記gc不在調用析構函數 } ~DisposableClass() { Dispose(false); } private void Dispose(bool disposing) { if(_disposed) return; //如果已經被回收,就中斷執行 if(disposing) { //TODO:釋放本對象中管理的托管資源 } //TODO:釋放非托管資源 _disposed = true; } }
- 可能存在的疑問
1. 既然gc是另外一線程執行的,為什么Dispose(bool)函數里不加鎖?
答:因為如果可以主動調用的時候,肯定此對象不是死對象,也不會被回收,因此不會同時調用到
2. 為什么析構函數調用的dispose(false)不釋放托管資源?
答:因為析構函數由gc來調用,gc會依次釋放所有的死對象(不可到達),釋放的順序是隨機的,如果在一個對象的析構里調用了一個本次gc已經釋放的對象,就會發生釋放兩次的錯誤。
- 這個講的也不錯,就是有點啰嗦:
https://blog.csdn.net/zrf2112/article/details/50644652