一般的なコードの場合、本当にオブジェクトを破棄する必要がありますか? ほとんどの場合、それを無視できますか、それとも、100% 不要になったと確信している場合は、常にオブジェクトを破棄することをお勧めしますか?
8 に答える
使い終わったらすぐにオブジェクトを破棄します。使い捨てオブジェクトは、CLR が本質的に認識していない貴重なリソースを保持するオブジェクトを表します。その結果、GC もリソースを認識せず、破棄可能なオブジェクトをいつ収集して、基礎となるリソースを解放する必要があるかについてインテリジェントな決定を下すことができません。
最終的に、GC はメモリ不足を感じ、偶然にオブジェクトを収集します (それ以上のことはありません)。決定論的な方法でオブジェクトを処分しないと、メモリ不足がほとんどない状態でリソースが不足した状態になる可能性があります。
これがどのように発生するかの簡単な例。基になるリソースを Win32 ハンドルと考えてみましょう。これらは非常に有限であり、かなり小さいです。多くの Foo オブジェクトを作成する操作を実行します。Foo オブジェクトは IDisposable を実装し、Win32 ハンドルの作成と破棄を担当します。それらは手動で解放されず、違いによって Gen2 ヒープになります。このヒープが解放されることはほとんどありません。時間の経過とともに、十分な数の Foo インスタンスが Gen2 ヒープに入り、使用可能なすべてのハンドルを占有します。したがって、メモリの使用量に関係なく、新しい Foo オブジェクトを作成することはできません。
実際、ハンドルを解放するには、インスタンスを解放するのに十分なプレッシャーを与えるために、1 回の操作で大量のメモリを割り当てる必要があります。
オブジェクトが IDisposable を実装している場合は、使い終わったらすぐに破棄する必要があります。最も簡単な方法は、 usingブロックで囲むことです。
using (SqlCommand cmd = new SqlCommand(conn)) {
cmd.ExecuteNonQuery();
}
Dispose()
を実装するすべての型で常に呼び出す必要がある理由IDisposable
は、通常、型がアンマネージ リソースを取得することを示すために使用されるためです。これらをできるだけ早く解放することが特に重要です。他の人が述べたように、using
これを行うための好ましい方法です。
それを見るにはいくつかの方法があります。1 つの方法は、オブジェクトが不要になったらすぐに破棄する必要があるかどうかを判断しようとします。管理されていないリソースを保持している場合、またはそれらが偶発的に破棄された場合。もう 1 つの観点は、オブジェクトが IDisposable を実装している場合、Dispose() を本当に呼び出す必要があるかどうかを判断するのはあなたの仕事ではなく、常に呼び出すことです。それが正しい道だと思います。オブジェクトの非公開実装をのぞき見して、それらをどのように使用すべきかを決定すると、変更される可能性のある実装に巻き込まれるリスクが高まります。例は、LINQ to SQL DataContext です。IDispose を実装しますが、ほとんどの場合、Dispose() を明示的に呼び出す必要なく、それ自体をクリーンアップします。とにかく明示的に処分するコードを書くのが私の好みですが、他の人はそれが必要ではないと示唆しています。
もちろん、これはすべて IDisposable を実装するオブジェクトに適用されます。GC が他のほとんどすべての処理をユーザー側で明示的なアクションを行わなくても処理することは事実ですが、GC の動作の機微について少し読む価値があります (今は疲れすぎて詳細を考えることができません)。オブジェクトを明示的に破棄し、さらに重要なのは、IDispose をいつ実装するかです。この問題に関するインターウェブには、多くの優れた記事があります。
前に述べたように、using(..) { ... } は IDisposable 実装者の友人です。
オブジェクトが IDisposable を実装している場合、アンマネージ リソースを保持している可能性が非常に高くなります。したがって、経験則として、直接または using ブロックを介して、オブジェクトの処理が完了した瞬間に Dispose を呼び出すことになります。GC に依存しないでください。それが IDisposable の目的であり、リソースを決定論的に解放するためです。
いいえ、管理されていないリソースを保持していない場合は、Dispose を呼び出すことで回避できます。ただし、クラスが管理されていないリソース、たとえば削除する必要がある一時ファイルを保持している場合は、Dispose を明示的に呼び出す必要があります。
Finalize メソッドで解放コードを記述することで Dispose の呼び出しを回避できますが、ガベージ コレクターがいつオブジェクトをファイナライズするかがわからないため、ガベージ コレクターに依存することになります。安全のために、アンマネージ リソースを保持するクラスを設計している場合は、Dispose メソッドと Finalize メソッドの両方で同じオブジェクト解放コードを記述できますが、その場合は、dispose メソッドで常に SuppressFinalize() を使用してください。オブジェクトが既にファイナライズ キューにある場合、Finalize() メソッドが呼び出されないようにするためです。
ほとんどの場合、GC の「機能」に依存します。古典的な例外は、リソースを大量に使用するインタラクションがある場合です。その場合は、明示的に破棄するのが最善です。
明白な例。
using (var conn = new SqlConnection(connString)) {}
ブロックを「使用する」ことは、オブジェクトが正しく破棄されることを保証する最もクリーンで堅牢な方法です。'Using' ブロックは、IDisposable を実装する任意のオブジェクトで利用できます。
オブジェクトを使い終わったら、それを忘れることができます。どこにも参照されていない限り、なくなったのと同じです。使用するメモリは、ガベージ コレクターが必要に応じて解放されます。