为什么windbg> !EEHeap -gc显示比VMMAP.exe小得多的托管堆?

时间:2014-04-30 14:44:36

标签: windbg sos vmmap

我有一个C#应用程序,其内存使用量会随着时间的推移而增加。我定期进行用户模式转储,加载sos后,运行!EEHeap -gc来监控托管堆大小。在windbg / sos中我看到它开始~14MB并且长到160MB,然后缩减到15MB,但应用程序“Private Bytes”从未显着下降。我已经确定了可以控制“私有字节”增加的活动,因此我可以控制内存增长的时间。

我尝试运行Vmmap.exe并注意到它报告了~360MB的托管堆,快速转储并使用windbg / sos / eeheap -gc我只看到15MB。

为什么我会看到这样不同的价值观? 托管堆真的是vmmap.exe报告的吗?

如何在windbg中检查托管堆的这个区域?

2 个答案:

答案 0 :(得分:6)

您无法使用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堆,整个过程需要更多的努力。因此,我通常采用快捷方式,如果您知道除了.NET之外没有其他任何调用VirtualAlloc()的东西,那就没问题了。输入!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%
...

答案 1 :(得分:0)

非常感谢您的详细解答。非常感谢。

我很清楚windbg vs VMmap访问/控制程序。由于我可以通过外部动作引起泄漏,我很确定,因为我静止了活动,所以样本之间的内存不会增长很多。

我一直依赖于!eeheap -gc的最后一行输出:

GC堆大小:大小:0xed7458(15561816)字节。

我认为这个数字必须是正在使用的托管堆的数量(其中包含未释放的对象)。我总结了“!eeheap -gc”为每个SOH和LOH报告的所有“大小”字节,它与上述值匹配。

我运行了VMmap,拍了一张快照并退出了VMmap。然后我用windbg附上了这个过程。您使用!地址的技巧最具启发性。我使用的是12处理器服务器系统,因此每个处理器都有SOH和LOH,即总和为12。取而代之的是“!eeheap -gc”的输出具有所有堆的段。我将它们全部输入“!address”并将它们的大小相加(加上!eeheap -loader报告的大小)。结果是335,108K,这是我期望在经过的时间内(600K内)看到的变化。 VMmap Managed Heap似乎是托管堆使用的所有内存段的总量(我没有检查保留的数字)。所以现在我明白为什么“!eeheap -gc”报告的总数远低于VMmap显示的总数。 谢谢!