12

編集:私の質問は、私が探していた主な答えを得ていません。私は明確ではありませんでした。私は本当に2つのことを知りたいです:

  1. Dispose()呼び出すことでメモリリークが発生することはありませんか?
  2. 大規模なプログラムがあり、IDisposable オブジェクトで Dispose() をまったく呼び出さない場合に起こりうる最悪の事態は何ですか?

オブジェクトに対してDispose()呼び出されない場合、メモリ リークが発生する可能性があるという印象を受けました。IDisposable

このスレッドでの議論によると、私の認識は正しくありませんでした。呼び出されない場合、メモリ リークは発生しませんDispose()

なぜわざわざ電話するのDispose()ですか?しばらくしてからではなく、すぐにリソースを解放するだけですか? Dispose()大規模なプログラムがあり、IDisposableオブジェクトをまったく呼び出さない場合に起こりうる最悪の事態は何ですか?

4

7 に答える 7

7

他のいくつかの回答は、それを呼び出さなくても済むことを示唆しているように見えますが、これは本当に悪いアドバイスです。常にDispose任意のIDisposableリソースを呼び出す必要があります。

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

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

関連参照:ガベージ コレクターは IDisposable.Dispose を呼び出しますか?

于 2013-04-10T02:07:46.653 に答える
3

Dispose を呼び出さなくても (* 間違った実装については注 2 を参照)、従来の「メモリ リーク」が発生することはありません (メモリはプロセスの最後まで解放されません)。

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

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

ノート:

  1. この回答は、メモリを管理するオブジェクトを破棄しないことによって発生する真のメモリリーク/メモリ割り当ての問題について明示的に語っています。IDisposableこのような慣行によって引き起こされる「真のメモリ リーク」がないことは事実ですが、ほとんどの人は、メモリ使用量の増加をメモリ リークと見なします (アプリケーションの存続期間中、静的リスト/辞書に大量のオブジェクトを格納するのと同様)。
  2. IDisposableネイティブ メモリを管理し、パターンを誤って実装するオブジェクトを作成できます。この場合、実際にネイティブ メモリをリークする可能性があります ( の呼び出しに関係なくDispose)。
  3. ほとんどの場合、実装するオブジェクトIDisposableはメモリをまったく管理しません。ほとんどの実用的な C# プログラムでは、このようなオブジェクトによって管理されるネイティブ リソースは、ファイル、ビットマップ、フォント、同期オブジェクト、COM ネイティブ オブジェクトなどのシステム リソースのハンドルです。それらをタイムリーに処分しないと、他の問題が発生します。

すべての物を適切に処分してください。しない言い訳はありません。

于 2013-04-10T04:27:58.837 に答える
3

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

要約すると、IDisposable の場合は Dispose() してください。

于 2013-04-10T02:03:09.117 に答える
2

私のため:

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

のもう 1 つの用途はDispose、コンポーネントの寿命を明示的に終了できることです。Form.Dispose()C# の winform で呼び出すと、フォームが閉じます。ただし、 については、明示的に呼び出しずに単独で呼び出すだけでは、接続が閉じられる保証はないSqlConnectionと人々は言いました。と の両方を呼び出すことをお勧めします。私はこれを試していません。DisposeCloseCloseDispose

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

同様の質問は、IDisposable を破棄する C#である可能性があります

于 2013-04-10T02:02:49.267 に答える
1

Dispose() を呼び出さないとメモリ リークが発生することはありませんか?

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

アプリケーションにメイン ウィンドウがあり、メイン ウィンドウへのイベント サブスクリプションを持つ子コントロールを作成するとします。Dispose でそれらのサブスクリプションを解除します。破棄しない場合、メイン ウィンドウは、アプリケーションを閉じるまで、子コントロールへの参照を保持できます。

大規模なプログラムがあり、IDisposable オブジェクトで Dispose() をまったく呼び出さない場合に起こりうる最悪の事態は何ですか?

最悪のケースは、アプリケーションを閉じるまで不要なメモリを解放しないことです。

もう 1 つの質問は、必要なときに IDisposable またはファイナライズを実装しない場合はどうなるかということです。

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

Dispose を呼び出す必要があるもう 1 つの理由は、ファイナライズを抑制することです。

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

于 2016-02-09T05:19:33.760 に答える