2011-07-28 11 views
11

answer I wroteへのコメントでは、メモリリークとIDisposableに関する議論がありましたが、実際の結論には至りませんでした。IDisposableを無視してメモリリークを引き起こすのでしょうか?

アンマネージリソースを処理するクラスは、おそらくIDisposableを実装します。それを無視してDisposeを呼び出すことも、usingにオブジェクトをラップすることも、アンマネージドリソースがリークすることになりますか?またはGCがオブジェクトを収集するときに適切にクリーンアップされますか?

私たちは、私が管理メモリリークが発生することはありませんアンマネージドリソースを扱うクラスがファイナライザなど

+0

http://www.bluebytesoftware.com/blog/2005/04/08/DGUpdateDisposeFinalizationAndResourceManagement.aspx –

+1

物事が正しく行われていると仮定すると、危険なことになります。しかしそれでも、これは関連しています:http://stackoverflow.com/questions/6652044/c-language-garbage-collection-suppressfinalize/6652318#6652318 –

+3

Finalizeが正しいため、正しいファイナライザは書き込めませんDisposeとは別のスレッドで呼び出されると、正常に呼び出された場合に呼び出されます。 –

答えて

14

メモリリークは発生しません。実際、Disposeはメモリ管理とはまったく関係ありません。

リソースリークが作成されます。 GCは通常、それをクリーンアップしますが、これはあまりにもまれで遅すぎる可能性があります。

Dispose(using)を省略すると、アプリの速度が遅くなったり、アプリがクラッシュすることさえあります。ファイルリソースやDb接続の場合、他のアプリケーションでも問題を引き起こす可能性があります。

+1

IDisposableを無視すると、制限された量のメモリ(IDisposableが正しく使用されている場合)で実行する必要のあるプログラムが無制限のメモリを必要とすることがあります。メモリのリークと見なされるプログラムのメモリ要件の不必要な無限の成長がIDisposableを無視すると、メモリリークが発生する可能性があります。 – supercat

+0

@Supercat:上記の理由により、合計balderdash。たぶんあなたは「限られた量のリソース」を意味するかもしれませんが、それは答えを繰り返すだけです。 –

+0

IEnumeratorがINotifyCollectionChangedEventにサブスクライブして、変化するコレクション(有用なパラダイム、btw、およびVisualBasic.Collectionクラスでサポートされているもの)の実際の列挙を可能にすると仮定します。コレクションと列挙子の両方に、ファイナライズを確実にするための複雑なロジックが含まれていない限り(そのようなロジックは簡単ではなく、相当なオーバーヘッドを追加します)、DisposedされていないIEnumeratorは、コレクションが列挙される回数には制限がないので... – supercat

9

含むIDisposableの正しい実装を、持っていると仮定することができます。 は、参照されているアンマネージコードのリークを引き起こします。しかしそれはそれよりも悪い:現代のシステム上のメモリは十分に豊富であり、あなたはしばしば悪い漏れをしばしば得ることができる。 Mozilla Firefoxを目撃してください:それは以前はふるいのように流出していましたが、何百万人もそれを使用して喜んでいました。

大きな問題は、メモリとはまったく関係がないかもしれない他のリソースです。例には、データベース接続、システム入出力ハンドル、ソケットハンドル、ファイルハンドルなどが含まれます。これらは、IDisposableを適切に使用するように注意していない場合、あなた自身のシステム上でサービス拒否状況を簡単に作成できるすべての項目です。

+0

永続オブジェクトの無制限数のイベント加入者を作成して放棄するプログラムでは、放棄されていない加入者の数が定数を超えて大きくならない場合でも、その加入者を保持するための無制限のメモリが必要ですまたは、そのことについては、1つ)。このような放棄されたサブスクリプションは、メモリリークの定義を確実に満たします(プログラムが入力シーケンスを処理するために必要なメモリの量は、それが保持する「有用な」状態の量に関して無制限です)。 – supercat

2

IDisposableオブジェクトにアンマネージメモリの割り当てを解除するファイナライザがある場合、ファイナライザが呼び出されたとき(GCによって収集され、ファイナライザキューに置かれた後)にメモリは空きになりますが、任意のファイナライザとDispose()が呼び出されることはありません。メモリがリークされ、プロセスが終了するときにのみ再要求されます。

0

私の知る限り、GCはDisposeを呼び出しません。明示的に呼び出すか、または使用する必要があります。したがって答えは:はい、Disposeで解放されたアンマネージリソースをクラスが処理する場合、Disposeを呼び出さないとクラスがリークします。

+3

これは、ファイナライザが実行されるまで "リーク"されるため、厳密には当てはまりません。これは、彼らが正しくIDisposableを実装したという大きな前提に基づいています。 – user7116

+2

しかし、適切なIDisposableクラスはデストラクタ(GC)内のリソースも解放します。 –

+1

@Henk Holterman:実際には、Finalizeを使用して不適切な放棄から回復できるIDisposableクラスは、そうする必要があります。しかしながら、このような回復は必ずしも実用的ではない。 *特定のオブジェクト*を安全に放棄できることを知らずにIDisposableオブジェクトを放棄するコードは、放棄されたオブジェクトを悪い状態にするIDisposableオブジェクトよりもはるかに壊れています。 – supercat

4

ただ、あなたが説明してきたが、具体的DB接続にかなり頻繁に起こるヘンクとジョエルの答え

に少しを追加します。 ADO.NET Performance counterNumberOfReclaimedConnectionsが追加されました。このカウンタトラック...

閉じるまたはDisposeがアプリケーションによって呼び出されなかったゴミ コレクションを再利用されている接続の数。 接続を明示的にクローズまたは廃棄しないと、パフォーマンスが低下します。

パフォーマンスの低下は通常、接続が解放されるのを待つ必要があります。これにより、メモリの問題ではなく、接続にタイムアウトが発生することもあります。

1

長命オブジェクトからイベントをサブスクライブするオブジェクトでIDisposableを呼び出すことができないと、サブスクライバのメモリ割り当てライフタイムがパブリッシャのメモリ割り当てライフタイムに拡張されます。パブリッシャの存続期間中にアタッチされ、放棄される可能性のあるサブスクライバ数に上限がない場合、これは無制限のメモリリークを構成します。

1

GC実行時の大きな問題はです。

あなたが好きならConsole.WriteLineにブレークポイントを入れて

class GcTest 
{ 
    private Stopwatch sw = new Stopwatch(); 
    public GcTest() 
    { 
     sw.Start(); 
    } 

    ~GcTest() 
    { 
     sw.Stop(); 
     Console.WriteLine("GcTest finalized in " + sw.ElapsedMilliseconds + " ms"); 
    } 
} 

を以下のクラスを取ります。

空のウィンドウを作成しますが、アプリケーションを構成し、フォームのLoadイベントでちょうどあなたのアプリケーションを実行し、実行するためのファイナライザを待つ新しいGcTest

private void Form1_Load(object sender, EventArgs e) 
{ 
    var gcTest = new GcTest(); 
} 

をインスタンス化します。
ほとんどの場合、アプリケーションを終了するまで実行されません。

関連する問題