Почему windbg>!EEHeap -gc показывает гораздо меньшую управляемую кучу, чем VMMAP.exe?

У меня есть приложение C#, использование памяти которого увеличивается со временем. Я периодически делал дампы в режиме пользователя и после загрузки sos запускаю!EEHeap -gc, чтобы отслеживать размер управляемой кучи. В windbg/sos я видел, как он запускается ~14 МБ и растет до 160 МБ, а затем сокращается до 15 МБ, но приложения "Private Bytes" никогда не уменьшаются значительно. Я идентифицировал активность, которая предотвращает увеличение "Частных байтов", чтобы я мог контролировать, когда происходит рост памяти.

Я попытался запустить Vmmap.exe и заметил, что он сообщает об управляемой куче ~360 МБ, сделал быстрый дамп и с помощью windbg/sos/eeheap -gc я вижу только 15 МБ.

Почему я вижу такие разные ценности? Является ли управляемая куча действительно тем, что сообщает vmmap.exe?

Как я могу проверить эту область управляемой кучи в windbg?

2 ответа

Вы не можете взломать приложение.NET с WinDbg и одновременно запустить VMMap. Это приведет к зависанию VMMap. Вы также не можете сделать это в обратном направлении: сначала запустите VMMap, затем разбейте WinDbg, а затем обновите значения в VMMap.

Поэтому значения, показанные VMMap, вероятно, никогда не равны, потому что числа взяты из другого момента времени. Различные моменты времени также могут означать, что сборщик мусора запущен. Если приложение не меняется так сильно, значения должны быть близки.

В моих тестах выделенная часть управляемой кучи в VMMap представляет собой сумму !eeheap -gc а также !eeheap -loader, что звучит разумно.

Учитывая выход !eeheap -gcмы получаем начало кучи GC в поколении 2 (11aa0000) и размер только 3,6 МБ.

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 МБ или 393,216 кБ, что в моем случае очень близко к 395,648 кБ, сообщенным VMMap.

Если у вас больше куч 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%
...

Большое спасибо за подробный ответ. Очень признателен.

Я ясно, о Windbg против VMmap доступа / управления программой. Поскольку я могу вызвать утечку из-за внешнего воздействия, я почти уверен, что, поскольку я прекращаю эту активность, память не будет сильно расти между выборками.

Я полагался на последнюю строку вывода из! Eeheap -gc:

Размер кучи GC: Размер: 0xed7458 (15561816) байт.

Я думаю, что это число должно быть количеством используемой управляемой кучи (с необработанными объектами в ней). Я суммировал все байты "size", сообщенные "! Eeheap -gc" для каждого SOH и LOH, и это соответствует вышеуказанному значению.

Я запустил VMmap, сделал снимок и вышел из VMmap. Затем я подключился к процессу с помощью windbg. Ваша техника использования адреса была очень поучительной. Я использую 12-процессорную серверную систему, поэтому для каждого процессора есть SOH и LOH, то есть 12 для суммирования. Если взять на себя инициативу, вывод "! Eeheap -gc" содержит сегменты для всех куч. Я передаю их все в "! Address " и суммирую их размеры (плюс размер, указанный в! Eeheap -loader). Результат составил 335,108K, что находится в пределах вариации, которую я ожидал увидеть за истекшее время (в пределах 600K). Кажется, что управляемая куча VMmap представляет собой общий объем всех сегментов памяти, выделенных для использования управляемой кучей (я не проверял зарезервированные числа). Итак, теперь я понимаю, почему общее количество, сообщаемое "! Eeheap -gc", намного меньше, чем то, что показывает VMmap. Спасибо!

Другие вопросы по тегам