web-dev-qa-db-ja.com

Dispose()メソッドのGC.SuppressFinalize(this)の目的は何ですか?

私は次のコードを持っています:

public void Dispose()
{
    if (_instance != null)
    {
        _instance = null;
        // Call GC.SupressFinalize to take this object off the finalization
        // queue and prevent finalization code for this object from
        // executing a second time.
        GC.SuppressFinalize(this);
    }
}

そのGC関連の呼び出しの目的を説明するコメントがありますが、なぜそこにあるのかまだわかりません。

usingブロックで使用されている場合のように、すべてのインスタンスが存在しなくなると、オブジェクトはガベージコレクションに向けられませんか?

これが重要な役割を果たすユースケースシナリオは何ですか?

29
mr.b

Disposeパターンを実装するときは、Dispose()を呼び出すファイナライザーをクラスに追加することもできます。これは、クライアントが呼び出しを忘れた場合でも、Dispose()alwaysが呼び出されるようにするためです。

Disposeメソッドが2回実行されないようにするには(オブジェクトがすでに破棄されている場合)、GC.SuppressFinalize(this);を追加します。ドキュメントは サンプル を提供します:

class MyResource : IDisposable
{
    [...]

    // This destructor will run only if the Dispose method 
    // does not get called.
    ~MyResource()      
    {
        // Do not re-create Dispose clean-up code here.
        // Calling Dispose(false) is optimal in terms of
        // readability and maintainability.
        Dispose(false);
    }

    // Implement IDisposable.
    // Do not make this method virtual.
    // A derived class should not be able to override this method.
    public void Dispose()
    {
        Dispose(true);
        // This object will be cleaned up by the Dispose method.
        // Therefore, you should call GC.SupressFinalize to
        // take this object off the finalization queue 
        // and prevent finalization code for this object
        // from executing a second time.
        GC.SuppressFinalize(this);
    }

    private void Dispose(bool disposing)
    {
        // Check to see if Dispose has already been called.
        if(!this.disposed)
        {
            // If disposing equals true, dispose all managed 
            // and unmanaged resources.
            if(disposing)
            {
                // Dispose managed resources.
                component.Dispose();
            }

            // Call the appropriate methods to clean up 
            // unmanaged resources here.
            resource.Cleanup()          
        }
        disposed = true;         
    }
}
34
Dirk Vollmar

ガベージコレクション:オブジェクトが参照されなくなったときに、GCはオブジェクトによって使用されたメモリを再利用します。

Dispose:IDisposableインターフェイスからのメソッドで、プログラマーが呼び出したときにすべてのマネージリソースとアンマネージリソースを解放します(直接またはusingブロックを介して間接的に) 。

Finalizer:すべての管理されていないリソースを解放するメソッド。メモリを再利用する前にGCによって呼び出されます。

管理対象リソース:StreamsやDbConnectionsなどのIDisposableインターフェイスを実装する.NETクラス。

アンマネージドリソース:マネージドリソースクラスにラップされたスタッフィング。 Windowsハンドルは最も簡単な例です。


今あなたの質問に答えるために:

GCは、クラスがファイナライザー(C#の〜ClassName)を宣言しているすべてのオブジェクトのリスト(ファイナライズキュー)を保持します。オブジェクトは、作成時にこのキューに入れられます。 GCは定期的に実行され、プログラムからアクセスできないオブジェクトがあるかどうかを確認します。次に、アクセスできないオブジェクトのいずれかがファイナライズキューから参照されているかどうかを確認し、これらをFreacheableキューと呼ばれる別のキューに入れ、残りは再利用されます。別のスレッドを使用して、Freacheableキュー内のオブジェクトのFinalizeメソッドを実行します。

次回GCを実行すると、以前にFreacheableキューにあったオブジェクトの一部がすでにファイナライズされているため、再利用の準備ができていることがわかります。ファイナライザーを使用してオブジェクトを削除するには、GCに少なくとも2サイクル(または、実行するファイナライズが多数ある場合はさらに多くのサイクル)が必要であることに注意してください。これにより、パフォーマンスが低下します。

SuppressFinalizeメソッドは、ファイナライザーを実行する必要がないことを示すフラグをオブジェクトヘッダーに設定するだけです。このようにして、GCはオブジェクトのメモリをすぐに再利用できます。上記の定義によると、Disposeメソッドはファイナライザー(およびそれ以上)と同じことを行うため、実行された場合、ファイナライズは不要になります。 SuppressFinalizeメソッドを使用すると、この事実を通知することでGCの作業を節約できます。さらに、ダブルリリースを回避するためにファイナライザーにチェックを実装する必要がなくなりました。 Disposeの唯一の問題は、それを呼び出すのはプログラマーの責任であるため、実行が保証されていないことです。そのため、ファイナライザーを気にする必要がある場合があります。


そうは言っても、ファイナライザーを作成する必要があるのはごくまれです。通常のアンマネージリソースの大部分にはマネージラッパーが既に存在し、マネージリソースはDisposeを呼び出すことで解放されるためです。独自のDisposeメソッドからのメソッド、そしてそこからのみ!ファイナライザーでは、Disposeメソッドを呼び出さないでください。


さらに読む

31
kicsit

ファイナライズできるオブジェクトは、最初のGC実行後も存続します。

通常、GCはオブジェクトが到達不能であることを検出すると、それを再利用します。オブジェクトがファイナライズ可能である場合、GCはそれを再利用しません。代わりに、それでも到達可能であると見なし(および、このオブジェクトが参照するすべてのオブジェクトなど)、ファイナライズのためにスケジュールします。オブジェクトは、ファイナライズされた後のある時点で到達不能であることが判明した場合にのみ再利用されます再び

これは、ファイナライズ可能なオブジェクトには追加のコストがかかることを意味します。オブジェクトは、より長い時間メモリに保持する必要があります。したがって、あなたが見る呼び出し:それが必要でないとき、ファイナライズを抑制することは価値があります。ここで、オブジェクトはファイナライズを使用して、ある時点で常に「破棄」されるようにします。明示的に廃棄された場合は、もう確定する必要はありません。

6
Thomas Pornin

タイプがファイナライザー(~MyType() { })を実装している場合、ガベージコレクターはそれを実行できません。ファイナライザーがアンマネージ型を処理するが、ユーザーがすでにDispose()を(明示的にまたはusing() { }ブロックを介して)呼び出して、それらのアンマネージ型を解放する場合に使用されます。

2
Jesse C. Slicer

MSDNから: GC.SuppressFinalize

このメソッドは、ファイナライザーを呼び出すときにシステムがチェックするオブジェクトヘッダーにビットを設定します。 objパラメーターは、このメソッドの呼び出し元である必要があります。

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

通常、オブジェクトが他のオブジェクトを参照していない場合、離散型のみを参照している場合、またはオブジェクト参照をすでにNULLにリセットしている場合は、これを使用します。

0
Craig Trader