2013-04-10 16 views
11

を編集してください:私の質問では、私が探していた主な回答が得られません。私ははっきりしていなかった。私は本当に2つのことを知りたいです:なぜDispose()を呼び出しますか?メモリリークは発生しませんか?

  1. Dispose()はメモリリークを引き起こしませんか?
  2. 大規模なプログラムを持っていて、IDisposableオブジェクトのいずれに対してもDispose()を呼び出さないと、最悪のことが起こりますか?

Dispose()IDisposableオブジェクトで呼び出されないとメモリリークが発生する可能性があります。

このthreadのディスカッションでは、私の認識は間違っていました。 Dispose()が呼び出されないとメモリリークは発生しません。

Dispose()を呼び出すのはどうしてですか?すぐにリソースをすぐに解放するのですか?大規模なプログラムを持っていて、Dispose()をあなたのIDisposableオブジェクトのどれにも決して呼ぶことができない場合に起こりうる最悪の事は何ですか?

+1

あなたはどのくらい怠け者になりたいのか、そしてガベージコレクタがどの程度暴力的になってほしいですか。 –

+0

'Dispose()'は管理されていないリソースの確定的なリリース用です。これ以上何もない。ガベージコレクタがファイルを閉じて他の場所で使用するのを待つのは本当に嫌です。 –

+0

[IDisposableインターフェイスの適切な使用]の可能な複製(http://stackoverflow.com/questions/538060/proper-use-of-the-idisposable-interface) –

答えて

2

Dispose()は、ガベージコレクタが解放しないリソース(データベース接続など)を解放することを目的としています。これらのリソースもファイナライザで解放する必要がありますが、ファイナライザはDispose()メソッドよりもはるかに遅いです。

10

Disposeは、リソースを解放するために使用されます。これは、クラスが管理されていないメモリを割り当てた場合、メモリを意味する可能性がありますが、オープンファイルやデータベース接続などのネイティブオブジェクトやリソースが多い場合があります。

管理対象外のリソースを持たないクラスでDisposeを呼び出すことはよくありますが、ディスポーザブルで管理されていないリソースを持つ可能性のある別のクラスが含まれていることがよくあります。

また、リソースが解放される順序を保証するために、確定的な確定を確実にするために開発者がdisposeを実装することが有用なこともあります。

また、disposeを実装するクラスには、Disposeが呼び出されない場合、resourcdesを解放するファイナライザがあることにも注意してください。ファイナライザを持つオブジェクトは、クラスなしのクラスとは異なるライフサイクルを持ちます。 GCの準備ができたら、GCはファイナライザを持っていることを確認し、GCの準備ができたらすぐにオブジェクトを収集するのではなく、ファイナライズキューに入れます。これは、オブジェクトが1回の余分なGC繰り返しのために存在することを意味します。 disposeを呼び出すと、実装は通常、GC.SuppressFinalize()を呼び出すため、ファイナライザを呼び出す必要はありません(通常は必須ではありません)。

クラスがIDisposableを実装する場合は、常にDispose()を呼び出す必要があります。私にとって

+0

それは役に立ちますが、私はまだ少し混乱しています。 Dispose()を呼び出さないためにメモリリークが発生する可能性がありますか? –

+0

IDisposableはメモリリークとは関係ありません。 –

+0

すべてのIDisposableクラスは、Dispose()を呼び出さないコードを消費する可能性を防ぐために、ファイナライザ/デストラクタを実装する必要がありますか? –

2

Disposeは()のスコープを使用して使用することができます。これにより、IDisposeableコンポーネントの寿命を判断するのに役立ちます。私は通常StreamWriter/ReaderまたはSqlConnectionクラスでこれを使用します。

もう1つのDisposeを使用すると、コンポーネントの寿命を明示的に終了できます。C#winformでForm.Dispose()を呼び出すと、フォームが閉じられます。しかし、SqlConnectionの場合、明示的にCloseを呼び出すことなく、Disposeだけを呼び出すだけでは、接続が閉じられるとは保証されません。 CloseDisposeの両方に電話するようにアドバイスしてください。私はこれを試していない。

さらに、Dispose()を呼び出した後、寿命が終わるのを待つのではなく、オブジェクトの寿命が終わっていることを知っているので、GCはメモリを解放できます。

似質問はC# disposing IDisposable

3

規則は、オブジェクトがIDisposableインターを実装する場合、あなたが処分を呼び出す()または「使用」のパターンを使用する必要があるということであるかもしれません。 Dispose()とデストラクタ(ファイナライザ)の実行を待つことの違いは、Dispose()がすぐに呼び出され、db接続、ファイル、デバイス、管理されていないオブジェクトなどのいくつかの重要なリソースを解放するために使用できることです。

要約すると - それがIDisposableならDispose()!

7

これ以外の回答がある場合は、と言っています。これは本当に悪いアドバイスです。 常にIDisposableリソースにDisposeと電話する必要があります。

一部の.NETオブジェクトには、「ファイナライザ」と呼ばれるものがあります。これは独自のクラスでも定義できますが、一般的なC#プログラマのコードではほとんど見られません。ファイナライザは、ガベージコレクタがオブジェクトを破棄するときに実行されるもので、となることがありますが、それはDisposeです。ただし、そのクラスの実装者がそのようにした場合に限ります。

ベストプラクティスは常にDisposeです。リソース上でDisposeを呼び出さないと、メモリリーク、接続リーク、オペレーティングシステムのリソースリーク、または他の種類の恐ろしさが発生する場所で使用したライブラリがたくさんあります。ガベージコレクタは、カスタムファイナライザを実装していないため、問題を解決しません。

は関連資料:Will the Garbage Collector call IDisposable.Dispose for me?

2

は廃棄が今まで(*間違った実装に注記2を参照のこと)はありません呼び出すことはありません(メモリはプロセスが終了するまで解放されることはありません)伝統的な"memory leak"を引き起こします。

メモリと関連して発生する「唯一の」ことは、将来、非決定論的な瞬間に解放されることです。

Dispose以外のオブジェクトの1つの興味深いケースは、非常に小さい管理対象オブジェクトが大量の管理されていないメモリを保持している(つまりWin32メモリ管理関数のいくつかのフレーバで割り当てられている、つまりHeapAlloc)場合です。この場合、管理されたメモリマネージャは、Gen2 GCをトリガするためにメモリの圧力を適切に検出できない場合があります(特にx86-32ビットプロセスの場合)。プロセスの管理メモリの割り当てが途中で失敗する可能性があります。この場合のもう1つの問題は、「GCが割り当て解除されるのを待つ」ことによるアドレス空間の断片化です(大部分がx86の場合も同様です)。ネイティブメモリの小さなチャンクには比較的大きなスペースが割り当てられ、大きなブロック管理されたメモリ管理に必要です。

注:

  1. この答えは、明示的にメモリを管理IDisposableオブジェクトを配置しないことにより、同棲についてtrue memory leaks /メモリ割り当ての問題を語っています。そのような練習によって引き起こされる "真のメモリリーク"がないことは事実ですが、ほとんどの人はメモリリークとしてメモリ使用量を増やすことを検討します(静的リスト/辞書に大量のオブジェクトをアプリケーションの存続期間保存するのと同様です)。
  2. ネイティブメモリを管理し、正しくIDisposableパターンを実装するオブジェクトを作成できます。この場合、(Disposeを呼び出しても)実際にネイティブメモリがリークする可能性があります。
  3. ほとんどの場合、IDisposableを実装するオブジェクトは、管理されたメモリをまったく使用しません。最も実用的なC#プログラムの場合、そのようなオブジェクトによって管理されるネイティブリソースは、ファイル、ビットマップ、フォント、同期オブジェクトまたはCOMネイティブオブジェクトなどのシステムリソースのハンドルです。タイムリーにそれらを廃棄しないと、他の問題が発生します。

すべてのオブジェクトを適切に廃棄してください。。言い訳はありません。

+0

+1これは役に立ちます。 Dispose()を呼び出さないとメモリ "リーク"は発生しませんが、メモリが必要以上に長く使用されて問題が発生する可能性があります。 –

+2

「Dispose」を呼び出さないと、マネージコードの領域内でも無制限のメモリリークが発生することがあります。他のオブジェクトからイベントにサブスクライブし、決してサブスクライブを解除しないオブジェクトは、そのメモリの寿命を後者のオブジェクトに拡張します。長期にわたるオブジェクトの存続期間中に無制限の数のオブジェクトが作成され、そこからのイベントをサブスクライブし、取り消されることなく放棄された場合、無制限のオブジェクトがメモリ内に保持されなければなりません。 – supercat

+0

@supercat - 良い点ですが、あなたが書いていることは本当のメモリリーク(ポインタが失われて決して解放されない無人のメモリ)ではなく、実際には無制限のメモリ使用であることに注意してください。 –

1

メモリリークが発生する可能性がありますか?

はい、もちろんです。以下はその一例です。

アプリケーションにメインウィンドウがあり、メインウィンドウへのイベントサブスクリプションを持つ子コントロールを作成するとします。あなたは彼らのDisposeについて退会します。破棄しない場合、メインウィンドウは、アプリケーションを終了するまで、子コントロールへの参照を保持することができます。

あなたが大規模なプログラムを持っていると があなたIDisposableをオブジェクトのいずれかに廃棄を()を呼び出すことはありません場合に発生することができます最悪の事態は何ですか?

アプリケーションを終了するまで、悪い場合があります。

また、IDisposableやファイナライズを必要なときに実装していない場合はどうでしょうか?

PCを再起動するまで、メモリリークが発生している最悪のケースは、そのメモリを保持しています。これは、管理されていないリソースがあり、dispose/finalizeを実装していない場合にのみ発生します。 Idisposableインターフェイスを実装してファイナライザを実装すると、ファイナライズプロセスによってDisposeが実行されます。

Disposeを呼び出すもう一つの理由は、ファイナライズを抑制するためです。

前に示したように、Finalizeメソッドでオブジェクトがあり、Disposeを呼び出さなかった場合。そのオブジェクトは、2つのGCサイクルの間、メモリに存在することができます。最初のサイクルでは、そのインスタンスをファイナライズ・キューにエンキューし、GCプロセス後にファイナライズを行います。したがって、次のGCサイクルだけがそのメモリを解放することができます。

関連する問題