いつGC.SuppressFinalize()を使用する必要がありますか?


287

.NETでは、どのような状況で使用する必要がありますGC.SuppressFinalize()か?

この方法を使用するとどのような利点がありますか?


ファイナライザとIDisposableに関するいくつかの質問を見てきましたが、stackoverflowにもGC.SupressFinalizeと弱参照について何かがあるはずです
Sam Saffron

弱参照はファイナライザに関してほとんど何もしないと思います。おそらく、それらについてより直接的な質問を投稿する必要があります。
マイケルバー

Yerp私は、弱い参照について別の質問を投稿するつもりでした。オブジェクトプールを構築するときに、これらすべてを結び付けることができます。また、ReRegisterForFinalizeによるオブジェクトの復活について質問する必要があります
Sam Saffron

回答:


296

SuppressFinalizeファイナライザを持つクラスによってのみ呼び出されるべきです。thisオブジェクトが完全にクリーンアップされたことをガベージコレクター(GC)に通知しています。

IDisposableファイナライザがある場合の推奨パターンは次のとおりです。

public class MyClass : IDisposable
{
    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // called via myClass.Dispose(). 
                // OK to use any private object references
            }
            // Release unmanaged resources.
            // Set large fields to null.                
            disposed = true;
        }
    }

    public void Dispose() // Implement IDisposable
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    ~MyClass() // the finalizer
    {
        Dispose(false);
    }
}

通常、CLRは、作成時にファイナライザーを使用してオブジェクトのタブを保持します(作成にコストがかかります)。 SuppressFinalizeオブジェクトが適切にクリーンアップされ、ファイナライザキューに移動する必要がないことをGCに通知します。これはC ++デストラクタのように見えますが、デストラクタのようには機能しません。

SuppressFinalizeあなたのオブジェクトは、ファイナライザキューで待機している長い時間を生きることができるよう最適化は、容易ではありません。あなたのことをSuppressFinalize気に他のオブジェクトを呼び出すように誘惑されないでください。それは、起こるのを待っている深刻な欠陥です。

設計ガイドラインでは、オブジェクトがを実装している場合はファイナライザは必要ないことを通知していIDisposableますが、ファイナライザがある場合IDisposableは、クラスの確定的なクリーンアップを可能にするために実装する必要があります。

ほとんどの場合、あなたは逃げることができるはずです IDisposableリソースをクリーンアップするです。オブジェクトがアンマネージリソースを保持している場合にのみファイナライザーが必要であり、それらのリソースがクリーンアップされることを保証する必要があります。

注:IDisposableコードがIDisposableオブジェクトを適切に破棄したかどうかをテストするために、コーダーが独自のクラスのビルドをデバッグするファイナライザを追加する場合があります。

public void Dispose() // Implement IDisposable
{
    Dispose(true);
#if DEBUG
    GC.SuppressFinalize(this);
#endif
}

#if DEBUG
~MyClass() // the finalizer
{
    Dispose(false);
}
#endif

1
最初のコードスニペットでは、推奨されるIDisposable + finalizerパターンがどのように見えるかを投稿しています。コードのデバッグは適切ですが、煩わしい場合があります。..アンマネージリソースを持つクラスを除いて、ファイナライザを回避することのみをお勧めします。安全なファイナライザコードを書くことは簡単ではありません。
ロバートポールソン

1
こんにちは、なぜファイナライザからのパラメータとしてfalseを指定してdisposeを呼び出す必要があるのですか?破棄が呼び出されず、破棄されない場合はどうなりますか?オブジェクトが破棄されたかどうかを確認し、実際のクリーンアップを実行するとどうなるでしょうか。
ドリーマー

3
@Dreamer-実装によって異なります。一般に、ファイナライザによってIDisposable.Dispose()実装に対してDisposeが呼び出されているかどうかを知りたい場合。ファイナライザから呼び出された場合は、プライベート参照が無効になっていると想定する必要があり、実際には多くのことはできません。ただし、IDisposable.Dispose()から呼び出された場合は、参照がまだ有効であることがわかります。
ロバートポールソン

32
実装するクラスIDisposableがでない場合は、ユーザー定義のファイナライザが含まれていない場合でも、sealedへの呼び出しを含める必要があります。これは、ユーザー定義のファイナライザを追加するが、保護されたメソッドのみをオーバーライドする派生型の適切なセマンティクスを保証するために必要です。GC.SuppressFinalize(this) Dispose(bool)
Sam Harwell 2013年

1
sealed@SamHarwellで言及されていないことは、派生クラスにとって重要です。クラスがシールされていない場合、CodeAnalysisはca1816 + ca1063になりますが、シールされたクラスはなしでも問題ありませんSuppressFinalize
ダッシュ1995

38

SupressFinalizeファイナライザで行われる作業はすべてすでに行われているため、ファイナライザを呼び出す必要がないことをシステムに通知します。.NETドキュメントから:

IDisposableインターフェイスを実装するオブジェクトは、IDisposable.Disposeメソッドからこのメソッドを呼び出して、ガベージコレクターがそれを必要としないオブジェクトでObject.Finalizeを呼び出さないようにすることができます。

一般的に、ファイナライザでクリーンアップされるすべてのDispose()メソッドをGC.SupressFinalize()クリーンアップする必要があるため、ほとんどのメソッドはを呼び出すことができます。

SupressFinalizeシステムがオブジェクトをファイナライザスレッドにキューイングしないようにする最適化を提供するものです。適切に記述されたDispose()/ finalizerは、への呼び出しの有無にかかわらず適切に動作するはずGC.SupressFinalize()です。



1
Dispose(true);
GC.SuppressFinalize(this);

オブジェクトにファイナライザーがある場合、.netは参照をファイナライズキューに入れます。

を呼び出しているのでDispose(ture)、オブジェクトがクリアされるため、このジョブを実行するためにファイナライズキューは必要ありません。

そのGC.SuppressFinalize(this)ため、ファイナライズキューの参照の削除を呼び出します。


0

クラスまたはその派生クラスが、ファイナライザを備えたオブジェクトへの最後のライブ参照を保持している場合は、GC.SuppressFinalize(this)またはGC.KeepAlive(this)これを保証する、悪そのファイナライザによって影響を受ける可能性がある任意の操作後のオブジェクトで呼び出さすべきことであるが、ファイナライザウォンその操作が完了するまで実行しません。

コストGC.KeepAlive()GC.SuppressFinalize(this)ファイナライザは、一般的に呼び出す必要がありますか、ファイナライザ、およびクラス持たない任意のクラスでは基本的に同じであるGC.SuppressFinalize(this)の最後のステップとして、後者の機能を使用して、Dispose()必ずしも必要ではないかもしれないが、それはしませんが間違っている。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.