32

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

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

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

4

5 に答える 5

35

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

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;         
    }
}
于 2010-06-14T15:42:43.267 に答える
34

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

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

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

マネージド リソースIDisposable: Streams や DbConnections など、インターフェイスを実装する任意の .NET クラス。

管理されていないリソース: 管理されたリソース クラスにラップされたスタッフィング。Windows ハンドルは、最も単純な例です。


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

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

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

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


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


さらに読む

于 2010-06-14T16:30:04.917 に答える
6

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

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

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

于 2010-06-14T15:46:12.057 に答える
2

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

于 2010-06-14T15:42:12.753 に答える
0

MSDNから:GC.SuppressFinalize

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

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

通常、これは、オブジェクトが他のオブジェクトを参照していない場合、ディスクリートタイプのみを参照している場合、またはオブジェクト参照をすでにNULLにリセットしている場合に使用します。

于 2010-06-14T15:43:28.537 に答える