9

これを従来の Dispose パターンと仮定します (devx から取得しましたが、多くの Web サイトで見られます)。

class Test : IDisposable
{
  private bool isDisposed = false;

  ~Test()
  {
    Dispose(false);
  }

  protected void Dispose(bool disposing)
  {
    if (disposing)
    {
      // Code to dispose the managed resources of the class
    }

    // Code to dispose the un-managed resources of the class

    isDisposed = true;
  }

  public void Dispose()
  {
    Dispose(true);
    GC.SuppressFinalize(this);
  }
}

を呼び出す理由がわかりませんGC.SupressFinalize(this)。これには、参照を無効にするなど、独自の管理対象リソースの破棄を記述する必要がありますか? 私は少し迷っています、認めなければなりません。誰かがこのパターンに光を当てることができますか?

理想的には、管理されていないリソースのみを破棄し、GC に管理された収集を単独で実行させたいと考えています。

実際、ファイナライザーを指定する理由もわかりません。いずれにせよ、コーダーは自分で dispose を呼び出す必要があります。それが単なるフォールバック メカニズムである場合は、削除します。

4

6 に答える 6

16

このパターンは、メソッドがクライアント コードによって呼び出されIDisposableた時点で、オブジェクトが決定論的にリソースをクリーンアップできるようにするために使用されます。Dispose

Disposeファイナライザーは、クライアント コードが何らかの理由で呼び出しに失敗した場合のフォールバックとしてのみ存在します。

クライアントコードが呼び出すと、リソースのクリーンアップがその場で実行され、ファイナライズ中に再度Dispose実行する必要はありません。この状況での呼び出しは、オブジェクトがファイナライズの余分な GC コストを負担しないことを意味します。SuppressFinalize

また、独自のクラスが管理対象リソースのみを使用する場合、ファイナライザーは完全に不要です。GC がすべての管理対象リソースを処理し、フォールバック ファイナライザーが必要かどうかをそれらのリソース自体に任せます。アンマネージリソースを直接処理する場合にのみ、独自のクラスのファイナライザーを考慮する必要があります。

于 2010-12-19T23:53:39.047 に答える
4

SuppressFinalizeは、カスタム ファイナライザーのみを抑制します。

他の GC 動作は変更されません。参照を明示的に無効にする必要はあり
ません。(早めに回収したい場合を除く)

ファイナライザーのないクラスと、 を呼び出したインスタンスとの間に違いはありませんSuppressFinalize

を呼び出すSuppressFinalizeと、 への余分な呼び出しが防止されDispose(false)、GC がいくらか速くなります。(ファイナライザーは高価です)

アンマネージ リソースを持たないクラスには、ファイナライザーを含めないでください。(シールされていない限り、引き続き を呼び出す必要がありSuppressFinalizeます。これにより、継承されたクラスがアンマネージ リソースを追加できるようになります)

于 2010-12-19T23:56:13.587 に答える
2

Msdn から: "このメソッドは、システムがファイナライザーを呼び出すときにチェックするオブジェクト ヘッダーにビットを設定します。obj パラメーターは、このメソッドの呼び出し元である必要があります。IDisposable インターフェイスを実装するオブジェクトは、IDisposable.Dispose からこのメソッドを呼び出すことができます。メソッドを使用して、ガベージ コレクターが Object.Finalize を必要としないオブジェクトに対して呼び出さないようにします。」

したがって、GC からの余分な呼び出しを防ぎます。オブジェクトがファイナライズされているときにファイナライザーメソッド内から呼び出された場合、オブジェクトはすでにファイナライズされているため、何もしません。それ以外の場合、GC はオブジェクトをファイナライズせずにメモリを再利用できるため、処理が高速になります。

于 2012-04-03T16:45:09.460 に答える
2

一部の派生クラスがファイナライザーを追加することを決定した場合に備えて、SuppressFinalize 呼び出しが存在します。通常の破棄が正常に完了した場合、ファイナライズは必要ありません。派生クラスが追加することを決定した場合でも、SuppressFinalize 呼び出しにより、ガベージ コレクションの実行と干渉が防止されます。

これが重要な理由を理解するには、ファイナライズをガベージ コレクションの一部としてではなく、ガベージ コレクションの前に発生するものと考える必要があります。クラスがファイナライズ (Finalize をオーバーライドする場合は作成時に自動) に登録されると、Finalization Queue と呼ばれる特別なリストに入れられます。 ファイナライゼーション キュー内のオブジェクト、またはキュー内のオブジェクトによって直接的または間接的に参照されるオブジェクトはガベージ コレクションできませんが、ファイナライゼーション キュー内のオブジェクトにキュー以外のルート参照がないことが判明した場合、オブジェクトがキューからプルされ、ファイナライザーが実行されます。ファイナライザーがディスパッチされている間、オブジェクトは収集できません (ディスパッチ中に参照が存在するため)。ファイナライザーが完了すると、通常はオブジェクトへの参照がなくなるため、そのオブジェクト (およびそれによって参照されるオブジェクト) は通常収集可能になります。

個人的には、SuppressFinalize はばかげていると思います。なぜなら、派生クラスにファイナライザーが必要な正当な理由が思いつかないからです。派生クラスが、親クラスが何も知らない管理されていないリソース (*) を追加しようとしている場合、それらのリソースを保持する目的で別のクラスを作成する必要があります。親クラスはそれへの参照を保持する必要があります。そうすれば、親クラス自体はファイナライズを必要とせず、親クラスによって参照されるオブジェクトがガベージ コレクションから不必要にブロックされることはありません。

于 2010-12-20T01:26:04.680 に答える
1

MSDNに記載されているように、Finalizeメソッドの実行にはコストがかかります。disposeを呼び出すことで、クラスはすでに自己ファイナライズされているため、ファイナライザーを呼び出す必要はありません。ファイナライザーは、Disposeがコード(またはインスタンスの「所有者」)から直接呼び出されない場合に実装されます。

于 2010-12-19T23:59:03.357 に答える