2008-08-21 34 views
20

.NETでメモリリークが発生する可能性があります。.NETでメモリリークが発生する

私は2つを知っている:

  1. 適切に解除登録しないEvent Handlers/Delegates
  2. は、Windowsフォームで動的な子コントロールを配置していない:

例:

// Causes Leaks 
Label label = new Label(); 
this.Controls.Add(label); 
this.Controls.Remove(label); 

// Correct Code 
Label label = new Label(); 
this.Controls.Add(label); 
this.Controls.Remove(label); 
label.Dispose(); 

更新:アイデアは(上記のような)あまりにも明白ではない一般的な落とし穴をリストすることです。通常、ガベージコレクタのためメモリリークは大きな問題ではないという考えがあります。以前はC++であったのとは異なります。


グレートディスカッションみんなが、.NETでオブジェクトに残された参照が存在しない場合、それはいくつかの時点でガベージコレクトになり、定義によって...私は明確にしましょう。だから、メモリリークを引き起こす方法ではありません。

管理された環境では、私が気づいていないオブジェクトへの意図しない参照があった場合、それはメモリリークとみなされます(私の質問の2つの例)。

このようなメモリリークが発生する可能性のあるさまざまな方法は何ですか?

+2

キース氏によると、サンプルではメモリリークは発生しません。 – tobsen

答えて

5

ファイナライザスレッドをブロックします。ファイナライザスレッドがブロック解除されるまで、他のオブジェクトはガベージコレクションされません。したがって、使用されるメモリの量は増加し、増加します。

さらに読書:http://dotnetdebug.net/2005/06/22/blocked-finalizer-thread/

+11

それはどういう意味ですか? –

+0

ファイナライザはシングルスレッドです。 「ファイナライズ」は、最終的に処分可能なオブジェクトが処分されたときに発生します。 1つの特定のアイテムを処分できない場合、何も処分されず、メモリが足りなくなります。 –

+0

それでは、コンテキスト内で 'ブロック'が意味するもの - ファイナライザ機能をオーバーライドしてコードラップするか、実行を完全に阻止するか? – Hardryv

14

包括的なリストを提供する方法はありません。これは「どのように濡れることができますか?」と非常によく似ています。

これは、IDisposableを実装するすべてのコンポーネントでDispose()を呼び出していることを確認してください。また、どのような種類の管理されていないリソースも消費するすべてのタイプでIDisposableを実装するようにしてください。

いつも、あなたのコードベースでFxCopのようなものを実行して、そのルールを適用するのを手伝ってください。使い捨て可能なオブジェクトがアプリケーションフレームワーク内にどれほど深く埋もれているのか驚くでしょう。

+0

FxCopを設定してそのルールを適用するにはどうすればよいですか? – Joel

2

予期しないメモリ使用量や実際のリークについてお聞きしますか?あなたが列挙した2つのケースは、まったくリークではありません。オブジェクトは意図したより長く周囲に張り付く場合です。

言い換えれば、それらはメモリリークと呼ばれる人には知られておらず、忘れてしまった参考文献です。

編集:またはガベージコレクタまたは管理されていないコードの実際のバグです。

編集2:これについて考えるもう1つの方法は、常にオブジェクトへの外部参照が適切にリリースされるようにすることです。外部とは、コントロールの外部にあるコードを意味します。そのような場合は、メモリを "リーク"できるケースです。

0

管理されていない言語でメモリリークを引き起こす可能性のあるものは、多くの場合、管理対象言語でメモリリークを引き起こす可能性があります。たとえば、bad caching policiesはメモリリークを引き起こす可能性があります。

しかし、グレッグとダニーが言ったように、包括的なリストはありません。有効寿命後にメモリを保持する結果となるものは、リークを引き起こす可能性があります。

2

毎回IDisposableを呼び出すのが最も簡単な場所で、コードベースで低値のメモリリークの果実をすべて取得する有効な方法です。しかし、必ずしも十分ではありません。たとえば、マネージコードが実行時に生成される方法とタイミングを理解すること、またアセンブリがアプリケーションドメインにロードされるとアンロードされることがなく、アプリケーションのフットプリントが増加する可能性があることを理解することも重要です。本当にリークが発生することはありません、それだけでGCのためのより多くの作業を行い

+2

途中です。 .NetのCompact Frameworkで開発すると、オブジェクトを適切に処分しないと、急いでデバイスがメモリを使い切ってしまうことがすぐに分かるので、ここでは一般化しないでください。あなたはGCがそれをするのを待つことはできません。 –

21

:次のように転がっ使い捨ての部品を残し

// slows GC 
Label label = new Label(); 
this.Controls.Add(label); 
this.Controls.Remove(label); 

// better 
Label label = new Label(); 
this.Controls.Add(label); 
this.Controls.Remove(label); 
label.Dispose(); 

// best 
using(Label label = new Label()) 
{ 
    this.Controls.Add(label); 
    this.Controls.Remove(label); 
} 

はネットのような管理された環境での問題の多くなることはありません - それはです管理された手段の大きな部分。

あなたは確かにアプリケーションを遅くします。しかし、あなたは何かのために混乱を残すことはありません。

+1

コントロールを置いたままにすることは非常に危険です。小さな使い捨てのアプリケーションでは問題ありませんが、実際のアプリケーションでは常に破棄するか、後悔してください。私を信じて、私はそこにいました。 – Niki

+1

私はこれを見直しました。危険なことです。これをテストするには、ループ内でSystem.Drawing.Bitmapを作成して削除します。すぐにOutOfMemoryExceptionが発生し、GCは役に立ちません。 –

+1

@modosansreves - ええ、確かにあなたのアプリを壊すでしょう。しかし、管理された 'OutOfMemoryException'を取得するので、そのアプリだけがクラッシュします。管理されていないメモリリークは、BSOD、ハング、またはマシン全体のクラッシュを引き起こします。 – Keith

4

アンマネージリソースが正しく処理されないようにするためのFinalize(またはFinalizerからのDispose呼び出し)メソッドの例外。 一般的なのは、プログラマと仮定して、どのオブジェクトが廃棄され、既に例外処理が行われた結果として廃棄されたピアオブジェクトを解放しようとし、残りのFinalize/Dispose from Finalizeメソッドが呼び出されないためです。

0

デッドロックのスレッドが根を解放することはありません。明らかに、デッドロックがより大きな問題を提起すると主張することができます。

デッドロックされたファイナライザスレッドは、残りのファイナライザがすべて実行されないようにし、すべてのファイナライズ可能オブジェクトが解放されないようにします(依然としてfreachableリストの根幹です)。

マルチCPUマシンでは、ファイナライザがスレッドをファイナライザを実行するよりも速くファイナライズ可能なオブジェクトを作成できます。それが持続される限り、あなたは記憶を「漏らす」でしょう。おそらくこれは野生で起こる可能性は低いですが、再現するのは簡単です。

ラージオブジェクトヒープが圧縮されていないため、断片化によってメモリがリークする可能性があります。

手動で解放する必要があるオブジェクトが多数あります。例えば。リースおよびアセンブリのないリモートオブジェクト(AppDomainをアンロードする必要があります)。

14

GridControl.DataSourceプロパティをBindingSourceクラス(http://msdn.microsoft.com/en-us/library/system.windows.forms.bindingsource.aspx)のインスタンスを使用せずに直接設定します。それはのBindingSourceクラスのMicrosoftのドキュメントであることおかしいhttp://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=92260

これは、プロファイラで追跡するために私にはかなり時間がかかりました私のアプリケーションの漏れは、最終的に私はマイクロソフトがに応答したことを、このバグレポートを発見した原因合法的な授業のようにそれを渡そうとしますが、私は彼らが通貨マネージャーに関する基本的なリークを解決し、データをグリッドコントロールにバインドするために作成したと思います。

これに気をつけて、私はそこに漏れのあるアプリケーションが絶対にあると確信しています!

+7

Wicked投稿。私たちは、綿密なクリーニングリソースを持ち、IDisposableを実装するすべてが世話をしていることを確認したモバイルアプリを持っています。そのすべての後でも、私たちは大量の使用後にフィールドで奇妙なクラッシュをまだ持っていました。我々はこの厳しいシナリオを持っていました!あなたは揺れる。 –

+1

lol +1 Mat Nadrofskyコメント – Drevak

1
  1. 不要になったオブジェクトへの参照を保持する。

他のコメント - Disposeが呼び出されるようにする方法の1つは、コード構造で可能なときに...を使用することです。

2

は、.NETのメモリリークを防ぐために:

1)「を用いて」構築物を採用(または「試して、最終的にはコンストラクト)を持つオブジェクトたび 『IDisposableを』インターフェイスが作成されます。

2)スレッドを作成したり、オブジェクトを静的または長期間のコレクションに追加する場合は、クラスを「IDisposable」にします。 C#の 'イベント'はコレクションであることを忘れないでください。

Tips to Prevent Memory Leaksの短い記事です。

1

私にとっては本当に予想外だったことの一つがこれです:

Region oldClip = graphics.Clip; 
using (Region newClip = new Region(...)) 
{ 
    graphics.Clip = newClip; 
    // draw something 
    graphics.Clip = oldClip; 
} 

どこにメモリリークがありますか?そうです、oldClipも処分したはずです! Graphics.Clipはゲッターが呼び出されるたびに新しい使い捨てオブジェクトを返すまれなプロパティの1つです。

3

私はこの議論に追加する4つの追加項目を有する:

  1. 終了スレッド(Thread.Abort())を適切にそのようなイベントを用意することなく、UIコントロールを作成したことをメモリにつながる可能性が首を長くして使用されています。

  2. Pinvokeで管理されていないリソースにアクセスし、それらをクリーニングしないと、メモリリークが発生する可能性があります。

  3. 大きな文字列オブジェクトを変更します。 GCが実際にはプログラムのフットプリントを確実にすることができないため、大きな文字列が頻繁に変更されると、システムがヒットする可能性があります最小。

  4. カスタム描画を実行するためにGDIオブジェクトを頻繁に作成します。 GDIの作業を頻繁に行う場合は、単一のgdiオブジェクトを再利用してください。

1

Tess Fernandezメモリ​​リークの検出とデバッグに関する素晴らしいブログ記事があります。 Lab 6Lab 7

関連する問題