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;} }可能存在的疑問
既然 gc 是另外一線程執行的,為什么Dispose(bool)函數里不加鎖?
因為如果可以主動調用的時候,肯定此對象不是死對象,也不會被回收,因此不會同時調用到哪里不太對,但又說不上來。
為什么析構函數調用的dispose(false)不釋放托管資源?
因為析構函數由 gc 來調用,gc 會依次釋放所有的死對象(不可到達),釋放的順序是隨機的,如果在一個對象的析構里調用了一個本次 gc已經釋放的對象,就會發生釋放兩次的錯誤。
總結
以上是生活随笔為你收集整理的C# Dispose模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: dotnet-httpie 0.2.0
- 下一篇: C# 中使用HttpClient读取大型