14

免責事項:IDisposable管理されていないリソースを扱う場合は、 を実装する必要があることはわかっています。コードの残りの部分は決定論的であり、可能な限り迅速にクリーンアップすることを保証するusing (...) { }(と同等) 必要があります。try {} finally { Dispose(); }また、GC はを呼び出さないDispose()ため、メソッドをオーバーライドしてFinalize()(デストラクタ構文を使用して C# で) を呼び出すことをお勧めしますDispose()。通常、GC は呼び出しますFinalize()(GC.SuppressFinalize()呼び出されていない場合)。

問題:using (SqlConnection...) { }邪魔にならないようにしたので、コードが制御不能になったために実行できないという奇妙なシナリオがあります。私は通常決定論を行うことDispose()ができますが、それを保証することはできません. Reflector を使用して逆アセンブルSqlConnectionし、Dispose() を使用していることを確認しましたが、盲目でない限り、ファイナライザー/デストラクタ (Finalize()または~SqlConnection()) はありません。それは、私ができない奇妙なケースでGCが接続を「クリーンアップ」(プールに送り返す)しないことを意味しますか? 決定的なものを見つけることができませんでした...

4

1 に答える 1

11

まあ、ファイナライズは廃棄ではないので、廃棄されません。

にはファイナライザーがありますが、のコンストラクターでSystem.ComponentModel.Componentは抑制されていSQLConnectionます。これは、100% 確実に必要ないことがわかっているファイナライザーを使用して継承する場合は良い考えですが、そうでない場合は悪い考えです。この場合、それは良い考えです。

SqlConnectionただし、これは「実際の」接続のラッパーであることを忘れないでください。実際、さまざまな接続状態を表す一連の変化するオブジェクトのラッパーである可能性が最も高いです。これは、「実際の」接続を効率的にプールできるようにするメカニズムの一部です。これは、呼び出すOpen()たびにプールから関連するオブジェクトを取得し、呼び出すたびにClose()(直接、Dispose()スコープから、またはスコープを離れることによって) using) それを返します。

ここで、管理されていないリソースまたは GC の関心事ではないものを直接保持するオブジェクトのみをファイナライズする必要があることを思い出してください。SqlConnection( の状態に応じてSqlConnection) アンマネージ リソース (または実際には、クラスのネストを介してより深い) を保持するオブジェクトである可能性があるオブジェクトを保持します。SqlConnectionしたがって、それ自体をファイナライズする必要はありません。SqlConnectionopenがopen でなくなる可能性のある 3 つの方法を考えてみましょうSqlConnection

  1. Close()と呼ばれます。これにより、実際の接続がすぐにプールに返されます (プールがない場合は閉じられます)。
  2. Dispose()と呼ばれます。これはClose()同じ効果で呼び出します。
  3. オブジェクトはガベージ コレクションされます。

さて、3 番目のケースでは、オブジェクトは実際の接続を持つオブジェクトへの参照を保持しています。また、そうする唯一のオブジェクトでもあります。そのため、そのオブジェクトもガベージ コレクションの対象になります。ファイナライザーがある場合 (これ以上の巧妙なトリックが行われていないとは思いませんが、おそらくそうです)、そのファイナライザーによってファイナライザー キューに入れられ、最終的にファイナライズされます。

ファイナライザーがある場合SqlConnection、実際の効果は次のとおりです。

  1. バグのあるコードが発生する可能性があります (ファイナライズ可能なメンバーがファイナライズされているかどうかわからないため、ファイナライザー コードでファイナライズ可能なメンバーを処理するのは困難です)。
  2. 物事が遅くなる可能性があります (実際の接続はいずれにせよファイナライズされますが、せいぜいファイナライズと GC が遅くなるだけです)。
  3. とにかくここで何もする必要はありません (実際の接続はここで何の助けもなしに確定されます)。

したがって、ファイナライザーを に置くことSqlConnectionは、勝利なしの敗北です。また、実際の接続が最終的に完了することを願っています。

とはいえ、まだ理想にはほど遠いものであり、接続がリークする可能性は依然として非常に高いです。Close()電話や処分ができない理由を正確に説明していただけますか? 接続を管理するコードが close を呼び出さない可能性はありますか (オブジェクトはその日をどこかで終了し、そこで閉じる必要があります)。

IDataReaderから供給される やオブジェクトが完了できるようにするために、それを存続させる必要がありますIDataReaderか? その場合、CommandBehavior.CloseConnectionフラグを使用して、リーダーを閉じる (または破棄する) ことで接続を閉じることができますか? この後者のケースは、接続がスコープを未処理のままにしなければならなかったことを思い出すことができる唯一のケースに関するものです。

于 2010-09-03T16:42:28.493 に答える