为啥 windbg> !EEHeap -gc 显示的托管堆比 VMMAP.exe 小得多?
Posted
技术标签:
【中文标题】为啥 windbg> !EEHeap -gc 显示的托管堆比 VMMAP.exe 小得多?【英文标题】:Why does windbg> !EEHeap -gc show a much smaller managed heap than VMMAP.exe?为什么 windbg> !EEHeap -gc 显示的托管堆比 VMMAP.exe 小得多? 【发布时间】:2014-06-16 22:58:48 【问题描述】:我有一个 C# 应用程序,其内存使用量随时间增加。我已经定期进行用户模式转储,并在加载 sos 后,运行 !EEHeap -gc 来监控托管堆大小。在 windbg/sos 中,我看到它从 14MB 开始增长到 160MB,然后缩小到 15MB,但应用程序“Private Bytes”从未显着减少。我已经确定了导致“Private Bytes”增加的活动,因此我可以控制何时发生内存增长。
我尝试运行 Vmmap.exe 并注意到它报告了大约 360MB 的托管堆,快速转储并使用 windbg/sos/eeheap -gc 我只看到 15MB。
为什么我会看到如此不同的价值观? 托管堆真的是 vmmap.exe 报告的内容吗?
如何在 windbg 中检查托管堆的这个区域?
【问题讨论】:
【参考方案1】:您不能使用 WinDbg 闯入 .NET 应用程序,然后同时运行 VMMap。这将导致 VMMap 挂起。你也可以不做相反的事情:先启动VMMap,然后进入WinDbg,然后刷新VMMap中的值。
因此,VMMap 显示的值可能永远不会相等,因为这些数字来自不同的时间点。不同的时间点也可能意味着垃圾收集器已经运行。如果应用程序没有发生太大变化,则值应该接近。
在我的测试中,VMMap 中托管堆的已提交部分是!eeheap -gc
和!eeheap -loader
的总和,这听起来很合理。
鉴于!eeheap -gc
的输出,我们在第 2 代 (11aa0000) 处开始 GC 堆,大小仅为 3.6 MB。
Number of GC Heaps: 1
generation 0 starts at 0x0000000011d110f8
generation 1 starts at 0x0000000011cd1130
generation 2 starts at 0x0000000011aa1000
...
GC Heap Size 0x374a00(3623424)
!address
提供详细信息:
...
+ 0`11aa0000 0`11ef2000 0`00452000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE <unknown>
0`11ef2000 0`21aa0000 0`0fbae000 MEM_PRIVATE MEM_RESERVE <unknown>
0`21aa0000 0`21ac2000 0`00022000 MEM_PRIVATE MEM_COMMIT PAGE_READWRITE <unknown>
0`21ac2000 0`29aa0000 0`07fde000 MEM_PRIVATE MEM_RESERVE <unknown>
+ 0`29aa0000 0`6ca20000 0`42f80000 MEM_FREE PAGE_NOACCESS Free
...
虽然没有记录,但我相信新段从 11aa0000 开始,由 +
符号表示。 GC 段在 29aa0000 结束,这也是下一段的起点。交叉检查:.NET 内存应在最后一列报告为 <unknown>
- 好的。
总 GC 大小(保留 + 已提交)为
?29aa0000-11aa0000
Evaluate expression: 402653184 = 00000000`18000000
这是 402 MB 或 393.216 kB,在我的情况下,它非常接近 VMMap 报告的 395.648 kB。
如果你有更多的 GC 堆,整个过程需要更多的努力。因此,我通常采用捷径,如果您知道除了调用 VirtualAlloc() 的 .NET 之外没有其他任何东西,那就可以了。键入!address -summary
,然后查看第一个<unknown>
条目:
--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
Free 144 7ff`d8a09000 ( 7.999 Tb) 99.99%
<unknown> 180 0`1a718000 ( 423.094 Mb) 67.17% 0.01%
...
【讨论】:
谢谢!我正在添加由于您的输入而发现的内容,作为澄清的另一个答案。添加评论太长了。 "这是 402 MB 或 393.216 kB,在我的情况下非常接近 VMMap 报告的 395.648 kB。"这背后的数学原理可以澄清吗? @rb_:对于程序员:402.653.184 字节 = 393.216 kB = 384 MB。对于硬盘供应商:402.653.184 字节 = 402 MB 哈哈哈!我的错误是我误读了原始声明。我将把它留在这里以提醒您咖啡很重要。【参考方案2】:非常感谢您的详细回答。非常感谢。
我很清楚 windbg 与 VMmap 对程序的访问/控制。由于我可以通过外部操作导致泄漏,因此我很确定由于我停止了活动,因此样本之间的内存不会增长太多。
我一直依赖 !eeheap -gc 的最后一行输出:
GC 堆大小:大小:0xed7458 (15561816) 字节。
我认为这个数字必须是正在使用的托管堆的数量(其中包含未释放的对象)。我将“!eeheap -gc”报告的每个 SOH 和 LOH 的所有“大小”字节相加,它与上述值匹配。
我运行了 VMmap,拍了一张快照并退出了 VMmap。然后我用windbg附加了这个过程。您使用 !address 的技术最具启发性。我使用的是 12 处理器服务器系统,因此每个处理器都有 SOH 和 LOH,即总和为 12。带头,“!eeheap -gc”的输出包含所有堆的段。我将它们全部输入“!address”并将它们的大小相加(加上 !eeheap -loader 报告的大小)。结果是 335,108K,这在我期望在经过的时间内看到的变化范围内(在 600K 以内)。 VMmap 托管堆似乎是托管堆使用的所有内存段的总量(我没有检查保留的数字)。所以现在我明白了为什么“!eeheap -gc”报告的总数比VMmap 显示的要少得多。 谢谢!
【讨论】:
如果我的回答对您有帮助,您可以按向上箭头进行投票。如果它完全回答了您的问题,您可以按复选标记将其设为接受的答案。以上是关于为啥 windbg> !EEHeap -gc 显示的托管堆比 VMMAP.exe 小得多?的主要内容,如果未能解决你的问题,请参考以下文章