4

これは私が確認するためだけのものです、私はこれを正しく理解しました:

IDisposalパターンを実装する大規模なリソースクラスがあります。これは、(設計上)複数回呼び出されるように実装する必要があります(もちろん、正確に1回呼び出そうとしても)。また、バックアップと同様に、Dispose()メソッドも呼び出すファイナライザーを実装します。手動で呼び出された場合、Dispose()はGC.SuppressFinalize(this)も呼び出します。

周りの処分パターンのいくつかの例があります。それらのほとんどは、破棄コードの最後でGC.SuppressFinalize(this)を呼び出します。クリーニングの前に、Dispose()メソッドの先頭で呼び出す方がよいと主張する人もいます。後で主張しますが、これにより、クリーンアップ中にGCがファイナライザーを同時に呼び出さないことが確実になります。

質問:
GC.SuppressFinalizeを最初に配置しても、それ以上の効果はないようです。まだ競合状態がありますよね?では、代わりにスレッドセーフな方法でDispose()を実装する必要があるというのは本当ですか?

4

3 に答える 3

4

GCは、「到達可能」ではないオブジェクトのみをクリーンアップします。

thisコードが実行されているクラスは、ポインターがスタック上にあるため、引き続き「到達可能」です。したがって、disposeの実行中は、ファイナライザーは呼び出されません。

SuppressFinalizeしたがって、最初に電話するか最後に電話するかは関係ありません。

以下のコメント提供者が示すように、CLR実装は、インスタンスメソッドの実行中にオブジェクトがガベージコレクション/ファイナライズされないことを保証するようには見えません。オブジェクトを存続させるために可能な唯一の「信頼できる」参照は、オブジェクトのメソッドを呼び出すために使用されるものですが、それについてステートメントを作成するためのJIT内部について十分に知らないため、動作が変わる可能性があります。

以下の議論にアクセスするために、ここに答えを残しておきます。

于 2011-01-17T08:47:59.883 に答える
3

一見生きているように見える参照が存在するときにオブジェクトがファイナライズされる可能性がある場合もありますが、それは、他にオブジェクトを参照するものがない場合にのみ発生する可能性があります。GC.SuppressFinalize(this)は、現在のオブジェクト'this'をアクティブに参照するため、GC.SuppressFinalizeが実行されるまでファイナライズされないことが保証されます。さらに、オブジェクト参照がオブジェクトを破棄するために存在し、Disposeメソッドで使用可能であったという事実は、オブジェクトが停止し、どこかにファイナライザー(独自のファイナライザー)がない限り、Disposeの実行が開始される前にファイナライザーをキューに入れることができなかったことを保証します。 、または他のオブジェクトのそれ)がそれを復活させました。

オブジェクトがファイナライズのスケジュールを立てられ、それを意識することなく復活する可能性があるシナリオがいくつかあるため、廃棄を保護し、冗長な操作からファイナライズすることは悪い考えではないかもしれません。ただし、Microsoftのパターンは適切ではありません。ファイナライズ可能なオブジェクトは、ファイナライズに必要のないオブジェクトへの参照を保持するべきではありません。オブジェクトがマネージドリソースとアンマネージドリソースの混合を保持する場合、アンマネージドリソースは独自のクラスに移動する必要があります(事実上、それらをマネージドリソースに変換します)。そのため、メインオブジェクトはマネージドリソースのみを保持します。

于 2011-01-17T16:30:19.237 に答える
1

Disposeは例外をスローしないでください。

Disposeのすべてのコードがスレッドセーフであることを確認して、呼び出されても奇妙なことをしないようにします。通常、変数がすでにnullであるかどうかのチェックを追加すると、うまくいくはずです。

Microsoftの例では、Dispose関数の最後にGC.SuppressFinalizeしか表示されていません。

于 2011-01-17T08:49:10.737 に答える