.NET にガベージ コレクションがある場合、なぜ明示的に呼び出す必要があるのIDisposable
でしょうか。
6 に答える
ガベージ コレクションはメモリ用です。非メモリ リソース (ファイル ハンドル、ソケット、GDI+ ハンドル、データベース接続など) を破棄する必要があります。IDisposable
実際のハンドルは、参照チェーンのかなり下にある可能性がありますが、これは通常、型の根底にあるものです。たとえば、参照先Dispose
のをXmlWriter
破棄するStreamWriter
、参照先の を破棄する、ファイル ハンドル自体を解放することができますFileStream
。
他のコメントを少し拡張します。
Dispose() メソッドは、アンマネージ リソースへの参照を持つすべてのオブジェクトで呼び出す必要があります。そのような例には、ファイル ストリーム、データベース接続などが含まれます。ほとんどの場合に機能する基本的なルールは次のとおりです。
ただし、他にも次の点に注意してください。
- dispose を呼び出しても、オブジェクトが実際に破棄されてメモリが解放されるタイミングを制御することはできません。GC はそれを私たちに代わって処理し、私たちよりもうまく処理します。
- Dispose はすべてのネイティブ リソースをクリーンアップし、Jon が示したように基本クラスのスタック全体をクリーンアップします。次に、SuppressFinalize() を呼び出して、オブジェクトを再利用する準備ができており、それ以上の作業は必要ないことを示します。GC の次の実行でクリーンアップされます。
- Dispose が呼び出されない場合、GC はオブジェクトをクリーンアップする必要があることを検出しますが、Finalize を最初に呼び出して、リソースが解放されていることを確認する必要があります。 Dispose を呼び出すと、オブジェクトを消去する前に GC をもう 1 つ実行する必要があります。これにより、オブジェクトは GC の次の「世代」に昇格します。これは大したことではないように思えるかもしれませんが、メモリ不足のアプリケーションでは、オブジェクトをより高い世代の GC に昇格させると、高メモリ アプリケーションが壁を越えてメモリ不足のアプリケーションになる可能性があります。
どうしても必要な場合を除き、独自のオブジェクトに IDisposable を実装しないでください。実装が不十分または不要な実装は、実際には状況を改善するどころか悪化させる可能性があります。適切なガイダンスは次の場所にあります。
オブジェクトはメモリの横にリソースを保持することがあるためです。GC はメモリを解放します。IDisposable は、他のものを解放できるようにするためのものです。
オブジェクトが保持するリソースがいつクリーンアップされるかを制御したいからです。
ほら、GCは機能しますが、そのように感じたときに機能します。それでも、オブジェクトに追加したファイナライザーは、2つのGCコレクションの後でのみ呼び出されます。これらのオブジェクトをすぐにクリーンアップしたい場合があります。
これは、IDisposableが使用される場合です。Dispose()を明示的に呼び出す(またはusingブロックの構文糖衣構文を使用する)ことにより、オブジェクトにアクセスして標準的な方法でそれ自体をクリーンアップできます(つまり、独自のcleanup()呼び出しを実装し、代わりに明示的に呼び出すことができます)
すぐにクリーンアップするリソースの例は、データベースハンドル、ファイルハンドル、ネットワークハンドルです。
using キーワードを使用するには、オブジェクトに IDisposable を実装する必要があります。 http://msdn.microsoft.com/en-us/library/yh598w02(VS.71).aspx
インターフェースはリソースの観点から説明されることがよくありますが、そのIDisposable
ような説明のほとんどは、「リソース」が実際に何を意味するのかを実際に考慮していません。
一部のオブジェクトは、追って通知があるまで、他のエンティティに損害を与えるために、外部エンティティに代わりに何かを行うよう依頼する必要があります。たとえば、ファイル ストリームを含むオブジェクトは、ファイル システム (接続された宇宙のどこにでもある可能性があります) に、ファイルへの排他的アクセスを許可するよう要求する必要がある場合があります。多くの場合、外部エンティティに対するオブジェクトの必要性は、オブジェクトに対する外部コードの必要性に結びついています。クライアント コードが前述のファイル ストリーム オブジェクトを処理するすべての処理を完了すると、たとえば、そのオブジェクトは関連付けられたファイルへの排他的アクセス (または任意のアクセス) を持つ必要がなくなります。
一般に、追加の通知があるまでエンティティに何かを行うよう依頼するオブジェクト X は、そのような通知を配信する義務を負いますが、X のクライアントが X のサービスを必要とする可能性がある限り、そのような通知を配信することはできません。の目的はIDisposable
、サービスが不要になったことをオブジェクトに知らせる統一された方法を提供することです。これにより、オブジェクトの代わりに動作していたエンティティ (存在する場合) に、サービスが不要になったことをオブジェクトが通知できるようになります。呼び出すコードはIDisposable
、オブジェクトが外部エンティティから要求したサービス (存在する場合) を知る必要も気にする必要もありません。これは、オブジェクトが外部エンティティIDisposable
に対する義務 (存在する場合) を履行するように単に招待するだけだからです。
物事を「リソース」の観点から言えば、オブジェクトは、追って通知があるまで外部エンティティに何かを行うように依頼したときにリソースを取得し (通常、必ずしもそうである必要はありませんが、何かの排他的使用を許可します)、リソースを解放します。外部エンティティのサービスが不要になったことを示します。リソースを取得するコードは、義務が発生するほど「もの」を取得しません。リソースの解放は「もの」を放棄するのではなく、義務を果たします。