質問

メモリ リークが発生していると思われる WindowsForms アプリを使用しているため、Redgate の ANTS Memory Profiler を使用して疑わしいオブジェクトを調べたところ、それらのオブジェクトは既に存在するオブジェクトによってのみ保持されていることがわかりました。 ファイナライザーキュー. 。なるほど、ファイナライザー キューとは何ですか?最適な定義を教えていただけますか?逸話的なアドバイスを教えていただけますか?

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

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

アップデート: これ レッドゲートの記事 役に立ちました。

役に立ちましたか?

解決

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

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

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

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

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

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

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

他のヒント

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

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top