.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
IDisposable
がでない場合は、ユーザー定義のファイナライザが含まれていない場合でも、sealed
への呼び出しを含める必要があります。これは、ユーザー定義のファイナライザを追加するが、保護されたメソッドのみをオーバーライドする派生型の適切なセマンティクスを保証するために必要です。GC.SuppressFinalize(this)
Dispose(bool)
sealed
@SamHarwellで言及されていないことは、派生クラスにとって重要です。クラスがシールされていない場合、CodeAnalysisはca1816 + ca1063になりますが、シールされたクラスはなしでも問題ありませんSuppressFinalize
。
SupressFinalize
ファイナライザで行われる作業はすべてすでに行われているため、ファイナライザを呼び出す必要がないことをシステムに通知します。.NETドキュメントから:
IDisposableインターフェイスを実装するオブジェクトは、IDisposable.Disposeメソッドからこのメソッドを呼び出して、ガベージコレクターがそれを必要としないオブジェクトでObject.Finalizeを呼び出さないようにすることができます。
一般的に、ファイナライザでクリーンアップされるすべてのDispose()
メソッドをGC.SupressFinalize()
クリーンアップする必要があるため、ほとんどのメソッドはを呼び出すことができます。
SupressFinalize
システムがオブジェクトをファイナライザスレッドにキューイングしないようにする最適化を提供するものです。適切に記述されたDispose()
/ finalizerは、への呼び出しの有無にかかわらず適切に動作するはずGC.SupressFinalize()
です。
そのメソッドDispose
はIDisposable
、を実装するオブジェクトのメソッドで呼び出す必要があります。これにより、誰かがDispose
メソッドを呼び出しても、GCがファイナライザを再度呼び出すことはありません。
クラスまたはその派生クラスが、ファイナライザを備えたオブジェクトへの最後のライブ参照を保持している場合は、GC.SuppressFinalize(this)
またはGC.KeepAlive(this)
これを保証する、悪そのファイナライザによって影響を受ける可能性がある任意の操作後のオブジェクトで呼び出さすべきことであるが、ファイナライザウォンその操作が完了するまで実行しません。
コストGC.KeepAlive()
とGC.SuppressFinalize(this)
ファイナライザは、一般的に呼び出す必要がありますか、ファイナライザ、およびクラス持たない任意のクラスでは基本的に同じであるGC.SuppressFinalize(this)
の最後のステップとして、後者の機能を使用して、Dispose()
必ずしも必要ではないかもしれないが、それはしませんが間違っている。