2009-08-12 19 views
6

メモリがリークするようなWindowsフォームアプリケーションがあるので、RedgateのANTSメモリプロファイラを使用して、疑わしいオブジェクトを見て、すでにファイナライザキューにあるオブジェクトのみが保持していることがわかります。 Finalizer Queueとは何ですか?あなたは私を最高の定義に向けることができますか?あなたは一言のアドバイスを分かち合うことができますか?ファイナライザキューとControl + ThreadMethodEntryとは何ですか?

また、ファイナライザキューのすべてのルートGCオブジェクトは、System.Windows.Forms.Control + ThreadMethodEntryという名前の "caller"という名前のオブジェクトです。私はそれがマルチスレッドのUIのやりとりに関係しているのを見ていますが、それ以上のことは分かりません。私の見た目の怠惰を許し、無知を認めましたが、これらのリソースはすべてベンダーのコンポーネント内に埋められています。私はこれらの問題についてベンダーに話していますが、私は会話をスピードアップするための指示が必要です。 ThreadMethodEntryのもっとも有用な定義を教えてください。一言一言?

また、ファイナライザキューのこれらのオブジェクトについても気にする必要がありますか?

更新:この​​3210は役に立ちました。

答えて

14

ファイナライザキューには、ファイナライザメソッドが定義されているすべてのオブジェクトが格納されます。ファイナライザは、ハンドルなどの管理されていないリソースを収集する手段であることを思い出してください。ガベージコレクタはゴミを収集すると、ファイナライザを持つオブジェクトをファイナライザキューに移動します。あとで、ガベージコレクタがこれらのオブジェクトを収集することを決定すると、メモリ圧力、GCヒューリスティック、および月の位相に応じて、待ち行列を歩いてファイナライザを実行します。

過去にメモリリークが発生していたのを見ると、ファイナライザキュー内のベンダーのオブジェクトはコードが冗長になる可能性がありますが、メモリリークはありません。通常、良いコードは、管理されたリソースと管理されていないリソースの両方を収集するDisposeメソッドを公開します。その場合、GC.SuppressFinalize()を介してfinalizerキューから自身を削除します。したがって、ベンダーのオブジェクトがDisposeメソッドを実装していて、コードがそれを呼び出さない場合は、ファイナライザキューに多数のオブジェクトが含まれる可能性があります。

ANTSで2つの時点のスナップショットを作成し、それらの間に作成されたオブジェクトを比較しようとしましたか?これは、漏洩した管理対象オブジェクトを識別するのに役立ちます。あなたはファイナライザが実行されたときにメモリが消えるかどうかを確認したい場合は

また、だけでテストするには、この方法を試してください。

 
System.GC.Collect(); 
System.GC.WaitForPendingFinalizers(); // this method may block while it runs the finalizers 
System.GC.Collect(); 

私は通常、このコードを実行することはお勧めしません。ちょっとした仕事をしてゴミをたくさん作ったのなら、それを実行したいかもしれません。例えば、私たちのアプリでは、私たちの関数の1つはMDIウィンドウを閉じた後に無駄になる約350 MBのゴミを作り出すことができます。これはゴミをたくさん残すことが知られているので、手動でガベージコレクションを強制します。

最後に開いたモーダルダイアログを保持するベースのWindows.Formsコードには、低レベルのプロパティキャッシュがあります。これはメモリリークの原因となる可能性があります。この参照を取り除く1つの確実な方法は、別の単純なダイアログを強制的に表示させ、上記のGCコードを実行することです。

+0

偉大な答えPaulに感謝します。それは、私が話しているオブジェクトリファレンスグラフです。リソースをクリーンアップした後、2番目のスナップショットの新しいオブジェクトを見ています。 IDisposableを実装するグラフのすべてのオブジェクトには、「このオブジェクトに対してDispose()が呼び出されました」というツールヒントがありますが、選択されたオブジェクトにはそのようなツールチップがありません。 – flipdoubt

+2

ThreadMethodEntryについての注意:私はそれらがUIスレッドのInvokeで使われていると思います。すべてのControlオブジェクトには、ThreadMethodEntry型のスレッドコールバックのキューがあります。コールバックはThreadMethodEntryをデキューして実行します。 各ThreadMethodEntryオブジェクトには、一連の内部フィールドがあります。これらのフィールドを調べると、これらのベンダーのオブジェクトのどれが呼び出されているか把握するのに役立ちます。あなたがANTSからその情報を得ることができるかどうかは思い出せませんが、WinDbg.dllとsos.dll(管理されたデバッガの拡張機能)を使用することができます。 "メソッド"デリゲートと "呼び出し元"コントロールを見てください。 –

+0

また、ThreadMethodEntryオブジェクトにはファイナライザが実装されていますが、Disposeメソッドはありません。完了すると、ファイナライザキューに移動します。 –

1

ファイナライザキューは、使用されなくなったオブジェクトインスタンスがGCによってファイナライズされるのを待っているキューです。このキュー内のすべてのオブジェクトはファイナライズされ、おそらくメモリリークはこれらのオブジェクトから直接得られるものではありません。しかし、これらのオブジェクトの1つは、アンマネージリソースをすべて解放しないことがあります。

ThreadMethodEntryクラスはIAsyncResultの実装であり、このクラスのインスタンスは通常、Invokeを使用してUIを更新するか、Begin */End *メソッドを使用して非同期操作を呼び出すときに作成されます。

0

Here's似たような問題を記述した良いブログ投稿。より技術的なレベルでは、SOS.dll(ブログの記事で説明されている)とSosex.dllを使用して、これらのThreadMethodEntryオブジェクトがメモリ内でぶら下がっている理由を理解するのに役立ちます。これらのWinDbg拡張には、他のオブジェクトがメモリ内の特定のオブジェクトを参照しているものを追跡できるコマンドがあります。

関連する問題