9

メモリをリークしているように見えるWindowsFormsアプリがあるので、RedgateのANTSメモリプロファイラーを使用して、疑わしいオブジェクトを調べ、それらがすでにFinalizerキューにあるオブジェクトによってのみ保持されていることを確認しました。素晴らしい、まさにファイナライザーキューとは何ですか?最良の定義を教えていただけますか?逸話的なアドバイスを教えてください。

また、ファイナライザキューのすべてのルートGCオブジェクトは、「caller」という名前のSystem.Windows.Forms.Control+ThreadMethodEntryオブジェクトのインスタンスです。マルチスレッドUIの相互作用に関与しているように見えますが、それ以上のことはよくわかりません。私の明らかな怠惰と認められた無知を許してください、しかしこれらのリソースはすべてベンダーのコンポーネントの中に埋もれています。私はこれらの問題についてベンダーと話し合っていますが、会話をスピードアップするために何らかの方向性が必要です。ThreadMethodEntryの最も有用な定義も教えていただけますか?逸話的なアドバイスはありますか?

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

更新:このRedGateの記事は役に立ちました。

4

3 に答える 3

20

ファイナライザキューは、ファイナライザメソッドが定義されているすべてのオブジェクトを保持します。ファイナライザーは、ハンドルなどの管理されていないリソースを収集する手段であることを思い出してください。ガベージコレクターは、ガベージを収集するときに、ファイナライザーを持つすべてのオブジェクトをファイナライザーキューに移動します。後のある時点で(メモリの負荷、GCヒューリスティック、および月の満ち欠けに応じて)、ガベージコレクターがこれらのオブジェクトを収集することを決定すると、キューをたどってファイナライザーを実行します。

過去にメモリリークを処理したことがあるので、ファイナライザキューにベンダーのオブジェクトがたくさんあるのを見ると、コードがお粗末になる可能性がありますが、メモリリークを示すものではありません。通常、適切なコードは、マネージリソースとアンマネージリソースの両方を収集するDisposeメソッドを公開し、そうすることで、を介してファイナライザーキューから自分自身を削除しますGC.SuppressFinalize()。したがって、ベンダーのオブジェクトがDisposeメソッドを実装していて、コードがそれを呼び出さない場合、ファイナライザーキューに多数のオブジェクトが含まれる可能性があります。

2つの時点の間でANTSにスナップショットを作成し、それらの間で作成されたオブジェクトを比較してみましたか?これは、リークされている管理対象オブジェクトを特定するのに役立つ場合があります。

また、ファイナライザーの実行時にメモリがなくなるかどうかを確認したい場合は、次のコマンドでテストしてみてください。

System.GC.Collect();
System.GC.WaitForPendingFinalizers(); //このメソッドは、ファイナライザーの実行中にブロックされる可能性があります
System.GC.Collect();

このコードを正常に実行することはお勧めしません。大量の作業を行って大量のゴミを作成した場合は、これを実行することをお勧めします。たとえば、私たちのアプリでは、関数の1つが約350 MBのガベージを作成し、MDIウィンドウを閉じた後に無駄になります。これは大量のガベージを残すことが知られているため、手動でガベージコレクションを強制します。

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

于 2009-08-12T20:47:30.487 に答える
1

ファイナライザキューは、使用されなくなったオブジェクトインスタンスがGCによるファイナライズを待機しているキューです。このキュー内のすべてのオブジェクトがファイナライズされ、メモリリークはこれらのオブジェクトの1つから直接発生したものではない可能性があります。ただし、これらのオブジェクトの1つが、管理されていないすべてのリソースを解放しない場合があります。

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

于 2009-08-12T20:30:51.847 に答える
0

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

于 2009-08-12T20:52:00.820 に答える