C# Dispose模式詳細分析


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM