11

かなり大きなWindowsフォームアプリケーションを開発しています。いくつかの顧客のコンピュータでは、OutOfMemory例外でクラッシュすることがよくあります。例外(UnhandledExceptionハンドラーから呼び出されたclrdump)の直後のアプリケーションの完全なメモリダンプを取得した後、「。NETMemoryProfiler」とwindbgを使用して分析しました。

メモリプロファイラーは、ライブオブジェクトインスタンスで130MBしか表示していません。興味深いのは、多くのオブジェクトタイプで、非常に多くの到達不能インスタンス(たとえば、22000到達不能Byte []インスタンス)が表示されていることです。ネイティブメモリの統計では、データのすべてのヒープで合計127MB(これは問題ありません)ですが、第2世代のヒープでは到達不能な133MB、大きなヒープでは640MB(問題ありません)を示しています。

windbgを使用してダンプを分析すると、上記の統計が確認されます。

!dumpheap -stat
..... acceptable object sizes...
79330a00   467216     30638712 System.String
0016d488     4804    221756612      Free
79333470    27089    574278304 System.Byte[]

アプリケーションは、実行時に多数の短いバッファーを使用しますが、それらをリークしません。!gcrootを使用してByte []インスタンスの多くをテストすると、ルートがなくなります。明らかに、これらのアレイのほとんどは、メモリプロファイラーによって示されるように到達不能です。

すべてが正常であることを確認するために、!finalizequeueは、ファイナライズを待機しているオブジェクトがないことを示します

generation 0 has 138 finalizable objects (18bd1938->18bd1b60)
generation 1 has 182 finalizable objects (18bd1660->18bd1938)
generation 2 has 75372 finalizable objects (18b87cb0->18bd1660)
Ready for finalization 0 objects (18bd1b60->18bd1b60)

また、ネイティブファイナライザーのスレッドスタックトレースをチェックして、ブロックされていないことを示します。

現時点では、GCがデータを収集しない理由を診断する方法はありません(プロセスのメモリが不足しているため、診断したいと思います。)

編集:以下の入力に基づいて、ラージオブジェクトヒープの断片化についてもう少し読みましたが、これが当てはまるようです。

この種のデータ(私の場合はさまざまなbyte [])に大きなメモリブロックを割り当て、この領域のメモリを自分で管理するためのアドバイスを見てきましたが、これはかなりハックな解決策のようで、私が期待するものではありませんそれほど特別ではないデスクトップアプリケーションの問題を解決するため。

断片化の問題は、LOH上のオブジェクトが存在中に再配置されないという事実(少なくともMicrosoftの多くの人々がブログで述べていること)によって引き起こされます。これは理解できますが、次のようなメモリのプレッシャーに達すると論理的に見えます。 OOMを取得する恐れがある場合は、再配置を実行する必要があります。

断片化が原因であると完全に信頼する前に私が心配する唯一のことは、LOH上の非常に多くのオブジェクトがgcroot参照を持たないことです-これは、LOHのガベージコレクションでも部分的にしか実行されないためですか?

現時点で私が知っている唯一の解決策は、事前に割り当てられたメモリブロックのカスタム管理であるため、興味深い解決策を紹介できれば幸いです。

どんなアイデアでも大歓迎です。ありがとう。

4

4 に答える 4

4

LOHは断片化の影響を受けます。この記事では、分析とそれを回避するための基本的な方向性について説明します。
たぶん、それらのbyte []バッファの「典型的な」使用法を示すコードを投稿できますか?

于 2009-10-10T23:08:58.233 に答える
2

いつものように、物事は少し違うことがわかりました。アプリケーションが大量のメモリを消費し、最終的にOOMになるユースケースを見つけました。これを見つける前に取得したダンプで奇妙だったのは、gcrootのないオブジェクトがたくさんあることでした-なぜそれが解放されて新しい割り当てに使用されなかったのか理解できませんでしたか?次に、OOMが発生したときにおそらく何が起こったのか、つまりスタックが巻き戻され、メモリを所有していたオブジェクトに到達できなくなったため、ダンプが実行されたことがわかりました。そのため、GCできるメモリがたくさんあるように見えました。

デバッグバージョンで(実際のメモリ状態のダンプを取得するために)行ったことは、適度に大きなオブジェクトを割り当てることができるかどうかをチェックするThreading.Timerを作成することです。割り当てられない場合は、それが示されます。 OOMの近くにあり、メモリダンプを取得するのに良い時期です。コードは次のとおりです。

private static void OomWatchDog(object obj)
{
 try                          
 {
   using(System.Runtime.MemoryFailPoint memFailPoint = 
          new System.Runtime.MemoryFailPoint(20))
   {
   }
 }
 catch (InsufficientMemoryException)
 {
   PerformDump();
 }
}
于 2009-10-12T19:38:49.040 に答える
1

Image.FromFile( "非画像ファイル")がOutOfMemoryExceptionをスローすることがあります。ゼロバイトファイルは、そのようなファイルの1つです。

于 2009-10-10T23:18:24.860 に答える
1

LOHが問題であると思われる場合は、LOH割り当てにブレークポイントがあると、正しい方向を示す可能性があります。あなたはおそらくこのようなことをすることができます

bp mscorwks!gc_heap :: alllocate_large_object "!clrstack;.echo*********ラージオブジェクトヒープの割り当て***********;g"

于 2009-10-27T15:06:10.320 に答える