2

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

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

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

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

4

2 回答 2

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 堆,整个过程需要更多的努力。因此,我通常采用捷径,如果您知道除了调用 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%
...
于 2014-04-30T22:46:29.987 回答
0

Thank you very much for the detailed answer. Much appreciated.

I'm clear on windbg vs VMmap access/control of the program. Since I can cause the leak by an external action, I'm pretty sure that since I quiesce the activity, memory won't grow much between samples.

I had been relying on the last line of output from !eeheap -gc:

GC Heap Size: Size: 0xed7458 (15561816) bytes.

I think this number must be the amount of managed heap in use (with un-free'ed objects in it). I summed all the "size" bytes reported by "!eeheap -gc" for each SOH and LOH and it matches the above value.

I ran VMmap, took a snap shot and quit VMmap. Then I attached to the process with windbg. Your technique of using !address was most enlightening. I'm using a 12 processor server system, so there are SOH's and LOH's for each processor, i.e 12 to sum. Taking your lead, the output from "!eeheap -gc" has the segments for all of the heaps. I feed them all into "!address " and summed their sizes (plus the size reported by !eeheap -loader ). The result was 335,108K which is within the variation I'd expect to see within the time elapsed (within 600K). The VMmap Managed Heap seems to be the total amount of all of the memory segments committed for use by the managed heap (I didn't check the Reserved numbers). So now I see why the total reported by "!eeheap -gc" is so much less than what VMmap shows. Thanks!

于 2014-05-01T19:07:45.283 回答