339

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

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

4

5 に答える 5

343

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
于 2008-09-29T23:56:03.623 に答える
43

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

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

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

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

于 2008-09-29T22:44:21.593 に答える
1

クラス、またはそれから派生したものが、ファイナライザーを使用してオブジェクトへの最後のライブ参照を保持している可能性がある場合、そのファイナライザーによって悪影響を受ける可能性のある操作の後にオブジェクトに対してまたはいずれGC.SuppressFinalize(this)かを呼び出す必要があります。GC.KeepAlive(this)その操作が完了するまで実行されません。

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

于 2018-04-26T23:05:22.277 に答える
0

そのメソッドはDispose、を実装するオブジェクトのメソッドで呼び出す必要がありますIDisposable。このようにして、誰かがメソッドを呼び出した場合に、GCがファイナライザーを再度呼び出すことはありませんDispose

参照:GC.SuppressFinalize(Object)メソッド-Microsoft Docs

于 2008-09-29T22:44:11.703 に答える