我们收到了一位客户发送的原生(完整)崩溃转储文件。在Visual Studio(2005)调试器中打开它后,我们发现崩溃是由realloc调用引起的,尝试分配一个大约10 MB的内存块。转储文件异常地大(1.5 GB,通常情况下不超过500 MB),因此我们得出结论,我们存在内存“泄漏”或失控的分配,这要么完全耗尽了进程的内存,要么至少使其碎片化程度足以导致realloc失败。(请注意,此realloc用于分配日志缓冲区,我们并不惊讶它在这里失败了,因为10 MB一次性分配是我们除了某些非常大且不能更改的缓冲区之外进行的最大分配之一——问题本身可能与该特定分配无关。)
编辑:在与Lex Li的评论交换之后,我应该补充说明:这对我们来说是不可再现的(目前)。这只是一个明显显示了失控内存消耗的客户端转储。
如果我们能够采样其中一些分配地址,然后检查进程映像中这些地址的使用情况,那么 - 假设大部分这些分配都是造成我们的“泄漏” - 我们可能会找出这些失控分配来自哪里。
不幸的是,我目前真的不知道如何从转储中获得更多信息。 我该如何检查此堆以查看一些“336”分配地址? 我如何在转储中搜索这些地址,然后如何找出转储中哪个指针变量(如果有)保存了这些地址? 任何有关DebugDiag、WinDbg或其他工具的使用提示都可以帮助!如果您对我上面的分析有任何异议,请告诉我们!谢谢!
主要问题:
现在我们有一个转储文件,但如何找出导致过量内存使用的原因?
目前我们所做的:
我们使用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或其他工具的使用提示都可以帮助!如果您对我上面的分析有任何异议,请告诉我们!谢谢!