24

お客様からネイティブ(完全)クラッシュダンプファイルを受け取りました。Visual Studio(2005)デバッガーで開くと、最大10MBのブロックを割り当てようとしたrealloc呼び出しが原因でクラッシュが発生したことがわかります。ダンプファイルは異常に大きかった(1.5GB-通常は500MB程度)。

したがって、プロセスのメモリを完全に使い果たすか、少なくとも再割り当てが失敗するのに十分なほど大幅にフラグメント化されたメモリ「リーク」または暴走割り当てがあると結論付けます。(このreallocは、ロギングバッファーを割り当てた操作用であり、ここで失敗したことは驚くことではありません。これは、一度に10MBが、非常に大きなかなり変更できないバッファーとは別に、より大きな割り当ての1つになるためです。問題それ自体は、この特定の割り当てとは関係がない可能性があります。)

編集:以下のLex Liとのコメント交換の後、追加する必要があります:これは(現時点では)再現できません。これは、暴走したメモリ消費を明確に示している1つの顧客ダンプです。

主な質問:

これでダンプファイルができましたが、過剰なメモリ使用量の原因をどのように特定できますか?

これまでに行ったこと:

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、またはその他のツールの使用に関するヒントは、本当に役に立ちます。また、上記の私の分析のいずれかに同意できない場合は、お知らせください。ありがとう!

4

3 に答える 3

11

あなたは出来る:

  • これらの 336 バイトのブロックを調べて、コンテンツがそれらを割り当てたものについて何かを伝えているかどうかを確認してください。そのために、私は通常、windbg を使用します。最初にブロックのサイズを取得するコマンドを実行してから、このサイズsize!heap -stat -h 0x01040000に渡し、そのサイズのすべてのブロックを一覧表示します。次に、メモリを表示する任意のコマンド (dc など) を使用してブロックを調べることができます。!heap -flt s
  • 問題を再現することはできませんが、そのサイズのブロックを割り当てている別のダンプを調べることができます。最初に、gflags.exeユーティリティ ( gflags -i your.exe +ust) を使用してスタック バックトレース機能を有効にします。次に、アプリケーションを実行してダンプを取得し、 を使用し!heap -flt sてブロックを一覧表示します。次に、コマンド!heap -p -a blockaddress は、ブロックを割り当てた関数のスタックをダンプします。
于 2011-01-26T14:55:29.597 に答える
4

windbg では、ヒープをクロールする必要のある which を使用してみてください!heap -l(しばらく時間がかかります。検索を特定のヒープに制限して高速化する方法がある場合があります)、どこにも参照されていないすべてのビジー ブロックを見つけることができます。そこからメモリ ウィンドウ ( alt+ 5) を開き、メモリ リークが疑われる割り当てサイズに一致するいくつかのエントリを調べます。運が良ければ、データが何であるかを特定するのに役立ついくつかの一般的なパターン、またはすぐに配置できるいくつかの ASCII 文字列が存在する可能性があります。

残念ながら、gflags を使用してユーザー モードのスタック トレースをオンにし、umdh を使用してメモリ スナップショットを作成しながら再現を試みる以外に、他に良い方法はわかりません。

于 2011-01-19T15:40:59.350 に答える
3

現在、ダンプはいくつありますか?

メモリ リークを追跡する適切な方法は、DebugDiag のメモリおよびハンドル リーク ルールをうまく利用することです。

その後、DebugDiag が新しいダンプで動作すると、メモリ使用量について詳しく知ることができます。

于 2011-01-23T01:43:36.833 に答える