.NETでは、どのような状況で使用する必要がありますGC.SuppressFinalize()
か?
この方法を使用するとどのような利点がありますか?
.NETでは、どのような状況で使用する必要がありますGC.SuppressFinalize()
か?
この方法を使用するとどのような利点がありますか?
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
SupressFinalize
ファイナライザーで実行されたはずの作業はすべて実行済みであるため、ファイナライザーを呼び出す必要がないことをシステムに通知します。.NETドキュメントから:
IDisposableインターフェイスを実装するオブジェクトは、IDisposable.Disposeメソッドからこのメソッドを呼び出して、ガベージコレクターがObject.Finalizeを必要としないオブジェクトを呼び出さないようにすることができます。
一般に、ほとんどのメソッドは、ファイナライザーでクリーンアップされるすべてのものをクリーンアップする必要があるため、Dispose()
を呼び出すことができるはずです。GC.SupressFinalize()
SupressFinalize
これは、システムがオブジェクトをファイナライザースレッドにキューイングすることをわざわざしないようにする最適化を提供するものにすぎません。適切に記述されたDispose()
/finalizerは、への呼び出しの有無にかかわらず正しく機能するはずGC.SupressFinalize()
です。
クラス、またはそれから派生したものが、ファイナライザーを使用してオブジェクトへの最後のライブ参照を保持している可能性がある場合、そのファイナライザーによって悪影響を受ける可能性のある操作の後にオブジェクトに対してまたはいずれGC.SuppressFinalize(this)
かを呼び出す必要があります。GC.KeepAlive(this)
その操作が完了するまで実行されません。
とのコストは、ファイナライザーを持たないクラスでは本質的に同じであり、ファイナライザーを持っているクラスは一般に を呼び出す必要がGC.KeepAlive()
あるため、後者の関数を の最後のステップとして使用することは必ずしも必要ではありませんが、そうではありません。間違っている。GC.SuppressFinalize(this)
GC.SuppressFinalize(this)
Dispose()
そのメソッドはDispose
、を実装するオブジェクトのメソッドで呼び出す必要がありますIDisposable
。このようにして、誰かがメソッドを呼び出した場合に、GCがファイナライザーを再度呼び出すことはありませんDispose
。