windows故障转储文件详细内存使用分析?

Posted

技术标签:

【中文标题】windows故障转储文件详细内存使用分析?【英文标题】:Detailed memory usage analysis of windows crash dump file? 【发布时间】:2011-06-11 17:31:24 【问题描述】:

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

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

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

【问题讨论】:

很好的问题,感谢您提供的信息和演练,遇到了类似的问题。顺便说一句,DebugDiag 现在位于microsoft.com/en-us/download/details.aspx?id=40336 我刚刚注意到上面提到的2.0版本不支持分析所以应该得到1.2版本:microsoft.com/en-us/download/details.aspx?id=26798 - 如果安装失败,创建一个名为“用户”的用户组 再次更新,2.x版本支持分析,他们只是将DebugDiag拆分成多个应用程序,即DebugDiag.Analysis.exe。此外,2.1 版现在可通过microsoft.com/en-us/download/details.aspx?id=42933 获得 【参考方案1】:

你可以:

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

【讨论】:

你的第一个子弹让我们走上了正轨:!heap -stat 显示了我在问题中已经提到的0x150 块。 !heap -flt s150 然后转储出一长串地址。然后检查其中一些用户块地址显示df ... 显示有效且一致的浮点值。所以我们知道这是一些浮点数组泄漏并且能够追踪到泄漏。 我应该早点看到你的回答。我总是被 !heap -flt 阻止,因为这不会给出任何堆栈回溯。但是直到我看到你的答案,我才知道, !heap -flt s 命令将显示堆栈回溯,只有在使用 gflags.exe(gflags -i your.exe +ust) 激活堆栈回溯功能后进行的转储.非常感谢。这真的很有帮助。【参考方案2】:

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

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

【讨论】:

【参考方案3】:

你现在有多少转储?

跟踪内存泄漏的正确方法是充分利用 DebugDiag 的 Memory and Handle Leak 规则。

然后当 DebugDiag 处理新的转储时,它可以更多地了解内存使用情况。

【讨论】:

我们只有一个转储。 // “充分利用 DebugDiag 的内存和处理泄漏规则”应该是什么意思?我还有哪些更多的转储选项? blogs.msdn.com/b/tess/archive/2010/01/14/… 谢谢,您链接到[使用 Debug Diag 1.1 调试本机内存泄漏][blogs.msdn.com/b/tess/archive/2010/01/14/… 的文章非常有用。不幸的是,当我们只有一个未启用诊断的转储时,它并没有多大帮助。 @Martin,使用 DebugDiag 中的泄漏规则重新捕获转储。您可以仔细配置泄漏规则,以便它可以为您生成多个转储。试试看,你会看到的。

以上是关于windows故障转储文件详细内存使用分析?的主要内容,如果未能解决你的问题,请参考以下文章

系统蓝屏获取内存转储文件

在Windows 7上禁用应用程序故障转储

性能测试之JVM的故障分析工具VisualVM

查找 C# 应用程序的故障转储文件

Valgrind - 打开 Windows 内存转储

如何分析windbg中的<unclassified>内存使用情况