GC.SuppressFinalize()をいつ使用する必要がありますか?
-
02-07-2019 - |
質問
.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
他のヒント
ファイナライザで行われる作業はすべて完了していることをシステムに伝えているため、ファイナライザを呼び出す必要はありません。 .NETドキュメントから:
IDisposableを実装するオブジェクト インターフェースはこのメソッドを IDisposable.Disposeメソッドを ガベージコレクターが でObject.Finalizeを呼び出す それを必要としないオブジェクト。
一般に、ほとんどのDispose()メソッドはGC.SupressFinalize()を呼び出すことができます。これは、ファイナライザでクリーンアップされるすべてのものをクリーンアップする必要があるためです。
SupressFinalizeは、システムがファイナライザスレッドにオブジェクトをキューイングしないようにする最適化を提供するものです。適切に記述されたDispose()/ finalizerは、GC.SupressFinalize()の呼び出しの有無にかかわらず適切に動作するはずです。
このメソッドは、IDisposableを実装するオブジェクトのDisposeメソッドで呼び出す必要があります。この方法では、誰かがDisposeメソッドを呼び出した場合、GCはファイナライザーを再度呼び出しません。
参照: http://msdn.microsoft.com /en-us/library/system.gc.suppressfinalize.aspx
Dispose(true);
GC.SuppressFinalize(this);
オブジェクトにファイナライザーがある場合、.netは参照をファイナライズキューに入れます
Dispose(ture)を呼び出しているため、オブジェクトをクリアするため、このジョブを実行するためにファイナライズキューは必要ありません。
GC.SuppressFinalize(this)を呼び出して、ファイナライズキューの参照を削除します。
クラスまたはその派生クラスがファイナライザを使用してオブジェクトへの最後のライブ参照を保持する場合、 GC.SuppressFinalize(this)
または GC.KeepAlive(this )
は、そのファイナライザによって悪影響を受ける可能性のある操作の後にオブジェクトで呼び出される必要があります。したがって、その操作が完了するまでファイナライザが実行されないようにします。
GC.KeepAlive()
および GC.SuppressFinalize(this)
のコストは、ファイナライザを持たないクラスと、通常、ファイナライザは GC.SuppressFinalize(this)
を呼び出す必要があるため、後者の関数を Dispose()
の最後のステップとして使用することは必ずしも必要ではありませんが、間違っている。