お客様からネイティブ(完全)クラッシュダンプファイルを受け取りました。 Visual Studio(2005)デバッガーで開くと、最大10MBのブロックを割り当てようとしたrealloc呼び出しが原因でクラッシュが発生したことがわかります。ダンプファイルは異常に大きかった(1.5GB-通常は500MB程度)。
したがって、プロセスのメモリを完全に使い果たしたか、少なくともreallocが失敗するのに十分なほど大幅にフラグメント化した、メモリ「リーク」または暴走した割り当てがあると結論付けます。 (このreallocは、ロギングバッファーを割り当てた操作用であり、ここで失敗したことは驚くことではありません。一度に10MBは、非常に大きなかなり変更できないバッファーとは別に、より大きな割り当ての1つになるためです。問題それ自体は、この特定の割り当てとは関係がない可能性があります。)
編集:以下のLex Liとコメントを交換した後、追加する必要があります:これは再現できません私たち(現時点)。これは、暴走したメモリ消費を明確に示す1つのcustomerダンプです。
これでダンプファイルができましたが、過剰なメモリ使用量の原因を特定するにはどうすればよいですか?
DebugDiagツール を使用してダンプファイル(いわゆるメモリ圧力アナライザー)を分析しました。これが得られたものです。
Report for DumpFM...dmp
Virtual Memory Summary
----------------------
Size of largest free VM block 62,23 MBytes
Free memory fragmentation 81,30%
Free Memory 332,87 MBytes (16,25% of Total Memory)
Reserved Memory 0 Bytes (0,00% of Total Memory)
Committed Memory 1,67 GBytes (83,75% of Total Memory)
Total Memory 2,00 GBytes
Largest free block at 0x00000000`04bc4000
Loaded Module Summary
---------------------
Number of Modules 114 Modules
Total reserved memory 0 Bytes
Total committed memory 3,33 MBytes
Thread Summary
--------------
Number of Threads 56 Thread(s)
Total reserved memory 0 Bytes
Total committed memory 652,00 KBytes
これは、ちょっとしたコンテキストを得るためだけのものでした。私が信じているより興味深いものは次のとおりです。
Heap Summary
------------
Number of heaps 26 Heaps
Total reserved memory 1,64 GBytes
Total committed memory 1,61 GBytes
Top 10 heaps by reserved memory
-------------------------------
0x01040000 1,55 GBytes
0x00150000 64,06 MBytes
0x010d0000 15,31 MBytes
...
Top 10 heaps by committed memory
--------------------------------
0x01040000 1,54 GBytes
0x00150000 55,17 MBytes
0x010d0000 6,25 MBytes
...
さて、ヒープを見て0x01040000
(1.5 GB)表示:
Heap 5 - 0x01040000
-------------------
Heap Name msvcr80!_crtheap
Heap Description This heap is used by msvcr80
Reserved memory 1,55 GBytes
Committed memory 1,54 GBytes (99,46% of reserved)
Uncommitted memory 8,61 MBytes (0,54% of reserved)
Number of heap segments 39 segments
Number of uncommitted ranges 41 range(s)
Size of largest uncommitted range 8,33 MBytes
Calculated heap fragmentation 3,27%
Segment Information
-------------------
Base Address | Reserved Size | Committed Size | Uncommitted Size | Number of uncommitted ranges | Largest uncommitted block | Calculated heap fragmentation
0x01040640 64,00 KBytes 64,00 KBytes 0 Bytes 0 0 Bytes 0,00%
0x01350000 1.024,00 KBytes 1.024,00 KBytes 0 Bytes 0 0 Bytes 0,00%
0x02850000 2,00 MBytes 2,00 MBytes 0 Bytes 0 0 Bytes 0,00%
...
とにかくこのセグメント情報は何ですか?
リストされている割り当てを見てください:
Top 5 allocations by size
-------------------------
Allocation Size - 336 1,18 GBytes
Allocation Size - 1120004 121,77 MBytes
...
Top 5 allocations by count
--------------------------
Allocation Size - 336 3760923 allocation(s)
Allocation Size - 32 1223794 allocation(s)
...
明らかに、MSVCR80ヒープは336バイトで3.760.923の割り当てを保持していることがわかります。これにより、メモリを大量の小さな割り当てでモップアップしたことがかなり明確になりますが、これらの割り当てがどこから来たのかに関する詳細情報を取得するにはどうすればよいですか?
どういうわけかこれらの割り当てアドレスのいくつかをサンプリングし、プロセスイメージのどこでこれらのアドレスが使用されているかを確認できれば、これらの割り当ての大部分が「リーク」の原因であると仮定すると、どこにあるかを見つけることができます。これらの暴走した割り当てはから来ました。
残念ながら、現時点では、ダンプからより多くの情報を取得する方法がわかりません。
このヒープを調べて、「336」の割り当てアドレスの一部を確認するにはどうすればよいですか?
これらのアドレスのダンプを検索するにはどうすればよいですか?次に、ダンプ内のどのポインター変数(存在する場合)がこれらのアドレスに保持されているかを見つけるにはどうすればよいですか?
DebugDiag、WinDbg、またはその他のツールの使用に関するヒントがあれば、本当に役に立ちます。また、上記の私の分析のいずれかに同意できない場合は、お知らせください。ありがとう!
あなたは出来る:
!heap -stat -h 0x01040000
を実行してから、このsizeを!heap -flt s
sizeは、そのサイズのすべてのブロックを一覧表示します。次に、メモリを表示する任意のコマンド(dcなど)を使用してブロックを調べることができます。gflags.exe
utility(gflags -i your.exe +ust
)を使用してスタックバックトレース機能をアクティブにします。次に、アプリケーションを実行し、ダンプを取得し、!heap -flt s
を使用してブロックを一覧表示します。次に、コマンド!heap -p -a
blockaddressは、ブロックを割り当てた関数のスタックをダンプします。現在、ダンプはいくつありますか?
メモリリークを追跡する適切な方法は、DebugDiagのメモリとハンドルリークルールをうまく利用することです。
次に、DebugDiagが新しいダンプで機能するときに、メモリ使用量について詳しく知ることができます。
Windbgでは、ヒープをクロールする!heap -l
を使用して(しばらく時間がかかりますが、検索を特定のヒープに制限して高速化する方法がある場合があります)、参照されていないすべてのビジーブロックを見つけることができます。どこでも。そこからメモリウィンドウを開きます(alt+5)そして、リークの疑いがある割り当てサイズに一致するエントリのいくつかを見てください。運が良ければ、データが何であるかを識別するのに役立ついくつかの一般的なパターンがありますが、すぐに配置できるいくつかのASCII文字列があります。
残念ながら、gflagsでユーザーモードのスタックトレースをオンにし、umdhを使用してメモリスナップショットを取得しながら再現しようとする以外に、他の良い方法はわかりません。