日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C#實現IDisposable接口釋放非托管資源_C#教程

作者:Laggage's ? 更新時間: 2022-07-08 編程語言

Reference

Why using finalizers is a bad idea

當在一個類中使用了另外一個實現了IDisposable的類作為一個成員屬性時, 此時這個類就有必要也去實現IDisposable接口, 以確保在合適的實際釋放非托管資源, 到底該如何正確的實現這個接口呢? 當然這只是需要實現IDisposable接口其中一種情況

完整示例

示例的Foo類中包含了一個Stream類型的_stream成員, 因此需要為Foo類實現IDisposable模式

public class Foo : IDisposable
{
    private bool _disposed;
    private readonly Stream? _stream;
    public Foo()
    {
        _stream = File.Create("1.txt", 2048);
    }
    ~Foo()
    {
        CleanupUnmanagedResources();
    }
    private void CleanupUnmanagedResources()
    {
        if (_disposed) return;
        // 釋放非托管資源
        _stream?.Dispose();
        _disposed = true;
    }
    public void Dispose()
    {
        CleanupUnmanagedResources();
        GC.SuppressFinalize(this);
    }
}

為什么要實現Foo析構函數

因為人性的弱點(?)

哈哈, 其實因為我們在使用Foo時可能會忘記手動調用其Dispose方法, 這個時候如果沒有析構函數的話, 很可能導致資源永遠得不到釋放最終釀成內存泄漏的慘劇.

當然啦, 在析構函數中釋放非托管資源可能會給GC帶來額外的開銷, 所以最好的做法是依然是使用using塊保證能夠及時的調用Dispose方法, 這里使用析構函數只是為了防止意外的發生. 至于為什么說在析構函數中釋放非托管資源會導致額外的GC開銷呢, 這涉及到GC回收過程,GC在處理包含析構函數的類時不會立即將此類回收, 而是會被GC標記為下一代, 這樣這個被標記為下一代的類只有在GC決定回收下一代的垃圾對象時, 才會被真正回收掉, 這樣一來就會導致額外的內存和性能開銷了.

Dispose方法中為什么要調用GC.SuppressFinalize

GC.SuppressFinalize方法可以告訴GC不需要在調用此類的析構函數(Finalizers)了;

因為在Foo類的析構函數中調用了Foo.CleanupUnmanagedResources方法, 當GC回收此類調用此類析構函數時, 有可能會導致兩次調用Foo.CleanupUnmanagedResources(第一次是Dispose方法中調用的)導致額外的開銷,

所以當我們手動調用了Foo.Dispose(通過是通過using語法糖)后, 就需要告訴GC, "你回收我的時候用不著調用我的析構函數了, 該釋放的資源我早就釋放掉了已經", 轉換成代碼就是GC.SuppressFinalize

原文鏈接:https://www.cnblogs.com/laggage/p/15734776.html

欄目分類
最近更新