2009-11-13 13 views
7

これは非常に基本的だと思いますが、自分で.NETを学習しているので、私はこの質問をしなければなりません。.NETのガベージコレクタに関する質問(メモリリーク)

私はCでコーディングするのに慣れています。ここには、すべてfree()が必要です。 C++/.NETでは、私はガベージコレクタについて読んだことがあります。私が理解しているところでは、(オブジェクトのスコープ内で)インスタンスが使用されなくなったとき、インスタンスはガベージコレクタによって解放されます。

これを念頭に置いて、少しテストアプリケーションを構築しました。しかし、同じことを数回(フォームを開く、閉じる、再開くなど)、メモリリークのために何かを得られなかったようです。そして大きな時間。

私はGoogleでこれを調べようとしましたが、初心者にとっては良いものは見つかりませんでした。

  1. ガベージコレクタは、もはや使用されなくなったり、例外を処理しなければならないすべてのオブジェクトを実際に解放していますか?私は何が欠けていますか?
  2. メモリリークを探すための無料ツールはありますか?
+7

メモリがリークしていることをどのように知っていますか? – Dmitry

+0

私はタスクマネージャのメモリに従っていました。私が下で作った他の2つのコメントを見てください。多分それは "漏れ"ではないが、それでもそれは迷惑である。 – Procule

+2

@Procule - CLR GCが動作するかどうか心配する必要があります。します。多くのC/C++コーダーがこれを使用しており、本当に満足しています。ただし、使用する/ IDisposableパターンについて学び、ドキュメントをチェックして、オブジェクトがIDisposableを実装しているかどうかを確認する必要があります。しかし、.NETの大きな利点は、この種のものを微調整することではありません。 – overslacked

答えて

11

ええ、ガベージコレクタはオブジェクトを使用しなくなったら解放します。私たちは通常、.NETのメモリリークを呼び出して何

は、より多くのようなものです:

  • あなたは(ごみ収集されません)外部リソースを使用して、それらを解放するために忘れています。これは通常、IDisposableインターフェイスを実装することで解決されます。
  • 与えられたオブジェクトへの参照はないと思いますが、ガベージコレクタはこれ以上使用していません。

さらに、メモリは必要なときにのみ再利用されます。つまり、ガベージコレクタは指定された時間にアクティブ化され、解放可能なメモリを特定して解放するコレクションを実行します。それまでは、メモリは要求されていないので、メモリが失われているように見えます。

ここでは、明確にするために、より複雑な回答を提供するつもりです。

まず、ガベージコレクタは独自のスレッドで実行されます。メモリを回収するためには、ガベージコレクタが他のすべてのスレッドを停止して、参照チェーンに従うことができ、何に依存するかを判断する必要があることを理解する必要があります。それがメモリがすぐに解放されない理由です。ガベージコレクタはパフォーマンスにある程度のコストがかかることを暗示します。

ガベージコレクタは内部的に世代ごとにメモリを管理します。非常に簡略化された方法では、長命、短命、および大きいサイズのオブジェクトの世代がいくつかあります。ガベージコレクタは、オブジェクトがある世代から別の世代に移動するたびにオブジェクトを移動させます。これは、長命の世代では短期間の世代でより頻繁に発生します。また、オブジェクトを再割り当てして、可能な限り連続した領域を確保します。コレクションを実行するには、コストのかかるプロセスです。

フォームを解放したときの効果を実際に見たい場合(範囲外になり、参照がなくなるとき)、GC.Collect()を呼び出すことができます。テストのためだけに行います。あなたが行っている作業とその影響を正確に把握しているケースを除いて、Collectを呼び出すことは非常に賢明ではありません。

さらに、IDisposeインターフェイスのDisposeメソッドについて説明します。

Disposeは通常のC++の方法ではデストラクタではなく、デストラクタではありません。 Disposeは、に、アンマネージドオブジェクトを確定的に取り除く方法です。例:何かしているために1GBのメモリを割り当てる外部COMライブラリを呼び出すとします。 Disposeを持たない場合はメモリがそこにあり、GCがコレクション内に入るまでのスペースを無駄にし、実際のオブジェクトデストラクタを呼び出すことによってアンマネージメモリを再利用します。したがって、すぐにメモリを解放したい場合は、Disposeメソッドを呼び出す必要がありますが、強制することはありません。

IDisposableインターフェイスを使用しない場合は、Finalizeメソッドで管理されていないリソースを解放する必要があります。 GCがオブジェクトの再生を試みると、オブジェクトデストラクタからFinalizeが自動的に呼び出されます。したがって、適切なファイナライズ方法がある場合、アンマネージメモリはいずれの方法でも解放されます。 Disposeを呼び出すと、確定的になります。

+0

(最初のボタン)アンマネージドオブジェクトを意味しますか? (2番目のボタン)他の人と同じことを言うようです。ですから、オブジェクトはまだ参照されていますが、オブジェクトによってはわかりません。知る方法はありますか?デバッガ(VS2008)は、ローカルについてのみ通知します。 (私はC/Linuxでコーディングするのに慣れています) – Procule

+0

@Jorge:+1、GCと世代の優れた説明。 (これは.NETに入るだけの人には非常に役立ちますが、悲しいことに私の経験では最も教訓のないアイテムの1つが示されています) –

+1

ええ、私は一般的に管理されていないオブジェクトを意味します。例えば、安全ではない固定ポインタは、オブジェクトを固定し、参照オブジェクトを再配置するのを止め、メモリの断片化を招き、結果として "無駄なスペース"が多くなる可能性があります。 –

3

GCは、オブジェクトが参照されなくなった時点で必ずしも実際には物を解放しません。 GCはいつの時点でそれを収集しますか?正確なタイミングはわかりませんが、メモリが必要な場合は、必要に応じてGCが収集を実行します。

+0

これは私が見つけたものです。タスクマネージャーを見ているうちに、しばらくしていくつかのメモリが解放されました。しかし、プログラムを開始するときには20メガバイト、80メガヘルツに行くと60メガヘルツに低下します。それはまだ40メガです。私は同じ「国家」にいるはずです。 – Procule

8

メモリリークがあると判断する原因は何ですか?ガベージコレクションでは、メモリが解放されたという保証はありませんすぐに、プロセスメモリがあるしきい値に達するか、または使用可能なヒープが使い果たされるまで、一般にGCが実行されません。正確なヒューリスティックは複雑で重要ではありません。したがって、プロセスのメモリが上がっても下がらないという事実は、必ずしもバグがあるわけではありません。 GCがあなたのプロセスをまだ浄化していないかもしれません。

あなたのオブジェクトへの参照はありませんか?あなたが気づいていない参照がある可能性があります。 .NETアプリケーションでのメモリリークの大部分は、メモリがまだどこかで参照されていることを人々が認識していないためです。

+0

私はあなたのことを理解しています。 (最初のコメントを参照してください "マイケルバー")。しかし、20megsから80megsに行く...それは私のために少し高いようです。オブジェクトを手動でDispose()する必要がありますか? – Procule

+0

あなたは 'Dispose()'をしたいですか?一般に、「IDisposable」インターフェースを実装するほとんどのオブジェクトは、配置されるべきである。私はC++/CLRについてはわかりませんが、C#では 'using'構造体でよく行われます。しかし、フォームオブジェクトの場合、人生は少し異なります。また、CLR自体のフットプリントが適度にあり、タスクマネージャで表示されるメモリレポートが不正確である可能性があることを理解してください。 (ANTSや別の良いプロファイラを使用して、実際に漏れがあることを確かめてください。) –

+0

ありがとう、あなたは私の2番目の質問に答えるようです。だから "ANTS"は私がメモリを管理/ルックアップするのを手助けするプログラムですか? (私の半分のコードはC++/CLIで、残りの半分はC#で(私は半分の方法を切り替えた、それはずっと簡単です!)) – Procule

0

WinDBGSOSSOSEX拡張を使用して、.NETでマネージヒープを見るために利用可能な無料ツールがありますが、(スタックに存在する対象物を見て、その後、それを一時停止し、プログラムを実行することが可能ですもっと重要なのは)他のどのオブジェクトがそれらを参照しているのか(ルーツ)は、GCがそれらを収集するのを妨げます。

4

これは質問のコメントではなく、回答として追加していますが、これはOPの質問では次のようになります。 using MSDNの文。 MSDNの IDisposableインターフェイス。

ここでは、問題の要点があります。オブジェクトデストラクタまでは慣れていたものです。あなたが正しくコーディングする方法について聞かれたことのすべては、あなたの潜在意識から叫んで、これは真実ではないと言って、それが真実なら間違ってひどいです。それは非常に異なっています。私が最初にそれを軽蔑したことを覚えているのは難しいです(私は誇らしげなC++開発者でした)。

私は個人的にあなたに約束します:それはうまくいくでしょう!

ここにもう1つの読み物があります: Destructors and Finalizers in Visual C++

+1

私はあなたがそれをどのように言うのが好きです。私は+1しますが、それを行うには15ポイントが必要です。ありがとう! – Procule

7

タスクマネージャは、メモリ使用量を調べる際のひどい方法です。ガベージコレクタがどのように機能するかを調べるには、CLRプロファイラをインストールし、アプリケーションを分析するために使用します。それはガベージコレクタが何をしているかを正確に伝えます。

How To: Use CLR Profilerを参照してください。

+0

アドバイスをいただきありがとうございます、私はCLRプロファイラを探しています。 +1 – Procule

+0

windbgやclrプロファイラで深く潜る前にperfmonを最初に実行すると、軽量でLOBヒープサイズ、Gen2ヒープサイズ、コレクション数などのカウンタがたくさんあります。また、CLRプロファイラ添付ファイルをサポートしていないICorProfilerを使用するので、先にプロファイルすることを決定する必要があります –

1

あなたはちょうどあなたがメモリリークを持っているかどうかを把握したい場合は、perfmonを見ているWindowsのコピーに付属:特に

.NET CLRメモリカウンタbytes in all heaps、この番号であれば着実に成長しています。

Gen 2ヒープサイズとラージオブジェクトヒープサイズを比較することで、さらに深く掘り下げることができます。前者が着実に成長していれば、大きなデータが漏れてしまいます。

リークがあることを確認したら、windbgで添付して、sos extensionsを使用して、何が漏れているのかを判断できます。

あなたが数ドルを費やすことができるなら、.NET Memory Profilerを見てください。