かなり大きな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のガベージコレクションでも部分的にしか実行されないためですか?
現時点で私が知っている唯一の解決策は、事前に割り当てられたメモリブロックのカスタム管理であるため、興味深い解決策を紹介できれば幸いです。
どんなアイデアでも大歓迎です。ありがとう。