Windows崩溃转储文件的详细内存使用情况分析?

时间:2011-01-19 12:17:29

标签: c++ debugging heap windbg crash-dumps

我们收到了客户的本机(完整)故障转储文件。在Visual Studio(2005)调试器中打开它表明我们遇到了由试图分配~10MB块的realloc调用引起的崩溃。转储文件非常大(1.5 GB - 通常它们更像是500 MB)。

因此,我们得出结论,我们有一个内存“泄漏”或失控的分配,要么完全耗尽进程的内存,要么至少将其分散到足以使realloc失败。 (请注意,这个realloc用于分配日志记录缓冲区的操作,我们不会感到惊讶,因为这里失败了,因为一次性使用10MB将是我们除了一些非常大的非常不可更改的缓冲区之外的更大分配之一 - - 问题本身可能与此特定分配无关。)

编辑:在下面的Lex Li评论交流之后,我应该补充:这对我们来说是不可复制的(目前)。它只是一个客户转储,清楚地显示内存消耗失控。

主要问题:

现在我们有一个转储文件,但是我们如何找到导致内存使用过多的原因?

到目前为止我们做了什么:

我们使用DebugDiag tool来分析转储文件(所谓的内存压力分析器),这是我们得到的:

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或任何其他工具的任何提示都可以提供帮助!另外,如果您不同意我上面的任何分析,请告诉我们!谢谢!

3 个答案:

答案 0 :(得分:10)

你可以:

  • 查看这些336字节的块,看看内容是否告诉您有关分配它们的内容。为此,我通常使用windbg。首先运行将为您提供块大小的命令!heap -stat -h 0x01040000,然后将此大小传递给!heap -flt s size ,它将列出所有块那个大小。然后,您可以使用任何显示内存的命令(如dc)查看该块。
  • 您无法重现该问题,但您可以查看另一个转储分配该大小的块的内容。首先使用gflags.exe实用程序(gflags -i your.exe +ust)激活堆栈回溯功能。然后运行您的应用程序,获取转储,并使用!heap -flt s列出块。然后命令!heap -p -a blockaddress 将转储分配该块的函数堆栈。

答案 1 :(得分:3)

在windbg中,您可以尝试使用!heap -l来抓取堆(需要一段时间,可能有办法将搜索限制到特定堆以加快速度)并查找所有繁忙的块没有在任何地方引用。从那里打开内存窗口( alt + 5 )并查看一些与您怀疑是泄密的分配大小相匹配的条目。幸运的是,可能会有一些常见的模式可以帮助您确定数据是什么或更好,还有一些可以立即放置的ascii字符串。

不幸的是,除了在使用gflags打开用户模式堆栈跟踪并使用umdh获取内存快照时尝试重现它,我真的不知道任何其他好的方法。

答案 2 :(得分:3)

你现在有多少转储?

跟踪内存泄漏的正确方法是充分利用DebugDiag的内存和句柄泄漏规则。

然后,当DebugDiag处理新转储时,它可以告诉更多有关内存使用情况的信息。