Как анализировать использование <unclassified> памяти в windbg
Это приложение Windows v4 для Windows, работающее на машине x64. В какой-то момент после нескольких дней бесперебойной работы потребление памяти в сервисе Windows кажется безумным, пока оно не сработает. Я смог поймать его на 1,2 ГБ и захватить дамп памяти. Вот что я получаю
Если я запустил! address -summary в windbg в моем файле дампа, я получаю следующий результат
! address -summary
--- Usage Summary ------ RgnCount ------- Total Size -------- %ofBusy %ofTotal
Free 821 7ff`7e834000 ( 7.998 Tb) 99.98%
<unclassified> 3696 0`6eece000 ( 1.733 Gb) 85.67% 0.02%
Image 1851 0`0ea6f000 ( 234.434 Mb) 11.32% 0.00%
Stack 1881 0`03968000 ( 57.406 Mb) 2.77% 0.00%
TEB 628 0`004e8000 ( 4.906 Mb) 0.24% 0.00%
NlsTables 1 0`00023000 ( 140.000 kb) 0.01% 0.00%
ActivationContextData 3 0`00006000 ( 24.000 kb) 0.00% 0.00%
CsrSharedMemory 1 0`00005000 ( 20.000 kb) 0.00% 0.00%
PEB 1 0`00001000 ( 4.000 kb) 0.00% 0.00%
-
-
-
--- Type Summary (for busy) -- RgnCount ----- Total Size ----- %ofBusy %ofTotal
MEM_PRIVATE 5837 0`7115a000 ( 1.767 Gb) 87.34% 0.02%
MEM_IMAGE 2185 0`0f131000 (241.191 Mb) 11.64% 0.00%
MEM_MAPPED 40 0`01531000 ( 21.191 Mb) 1.02% 0.00%
-
-
--- State Summary ------------ RgnCount ------ Total Size ---- %ofBusy %ofTotal
MEM_FREE 821 7ff`7e834000 ( 7.998 Tb) 99.98%
MEM_COMMIT 6127 0`4fd5e000 ( 1.247 Gb) 61.66% 0.02%
MEM_RESERVE 1935 0`31a5e000 (794.367 Mb) 38.34% 0.01%
-
-
--Protect Summary(for commit)- RgnCount ------ Total Size --- %ofBusy %ofTotal
PAGE_READWRITE 3412 0`3e862000 (1000.383 Mb) 48.29% 0.01%
PAGE_EXECUTE_READ 220 0`0b12f000 ( 177.184 Mb) 8.55% 0.00%
PAGE_READONLY 646 0`02fd0000 ( 47.813 Mb) 2.31% 0.00%
PAGE_WRITECOPY 410 0`01781000 ( 23.504 Mb) 1.13% 0.00%
PAGE_READWRITE|PAGE_GUARD 1224 0`012f2000 ( 18.945 Mb) 0.91% 0.00%
PAGE_EXECUTE_READWRITE 144 0`007b9000 ( 7.723 Mb) 0.37% 0.00%
PAGE_EXECUTE_WRITECOPY 70 0`001cd000 ( 1.801 Mb) 0.09% 0.00%
PAGE_EXECUTE 1 0`00004000 ( 16.000 kb) 0.00% 0.00%
-
-
--- Largest Region by Usage ----Base Address -------- Region Size ----------
Free 0`8fff0000 7fe`59050000 ( 7.994 Tb)
<unclassified> 0`80d92000 0`0f25e000 ( 242.367 Mb)
Image fe`f6255000 0`0125a000 ( 18.352 Mb)
Stack 0`014d0000 0`000fc000 (1008.000 kb)
TEB 0`7ffde000 0`00002000 ( 8.000 kb)
NlsTables 7ff`fffb0000 0`00023000 ( 140.000 kb)
ActivationContextData 0`00030000 0`00004000 ( 16.000 kb)
CsrSharedMemory 0`7efe0000 0`00005000 ( 20.000 kb)
PEB 7ff`fffdd000 0`00001000 ( 4.000 kb)
Во-первых, почему неклассифицированные появятся раз как 1,73 ГБ, а в другой раз - 242 МБ. (Ответ дан. Спасибо)
Во-вторых, я понимаю, что неклассифицированный может означать управляемый код, однако мой размер кучи в соответствии с! eeheap составляет всего 248 МБ, что на самом деле соответствует 242, но даже близко к 1,73 ГБ. Размер файла дампа составляет 1,2 ГБ, что намного выше, чем обычно. Куда я иду отсюда, чтобы узнать, что использовать всю память. Все в мире управляемых кучей находится под 248 МБ, но я использую 1,2 ГБ.
Спасибо
ИЗМЕНИТЬ
Если я делаю! heap -s, я получаю следующее
LFH Key : 0x000000171fab7f20
Termination on corruption : ENABLED
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-------------------------------------------------------------------------------------
Virtual block: 00000000017e0000 - 00000000017e0000 (size 0000000000000000)
Virtual block: 0000000045bd0000 - 0000000045bd0000 (size 0000000000000000)
Virtual block: 000000006fff0000 - 000000006fff0000 (size 0000000000000000)
0000000000060000 00000002 113024 102028 113024 27343 1542 11 3 1c LFH
External fragmentation 26 % (1542 free blocks)
0000000000010000 00008000 64 4 64 1 1 1 0 0
0000000000480000 00001002 3136 1380 3136 20 8 3 0 0 LFH
0000000000640000 00041002 512 8 512 3 1 1 0 0
0000000000800000 00001002 3136 1412 3136 15 7 3 0 0 LFH
00000000009d0000 00001002 3136 1380 3136 19 7 3 0 0 LFH
00000000008a0000 00041002 512 16 512 3 1 1 0 0
0000000000630000 00001002 7232 3628 7232 18 53 4 0 0 LFH
0000000000da0000 00041002 1536 856 1536 1 1 2 0 0 LFH
0000000000ef0000 00041002 1536 944 1536 4 12 2 0 0 LFH
00000000034b0000 00001002 1536 1452 1536 6 17 2 0 0 LFH
00000000019c0000 00001002 3136 1396 3136 16 6 3 0 0 LFH
0000000003be0000 00001002 1536 1072 1536 5 7 2 0 3 LFH
0000000003dc0000 00011002 512 220 512 100 60 1 0 2
0000000002520000 00001002 512 8 512 3 2 1 0 0
0000000003b60000 00001002 339712 168996 339712 151494 976 116 0 18 LFH
External fragmentation 89 % (976 free blocks)
Virtual address fragmentation 50 % (116 uncommited ranges)
0000000003f20000 00001002 64 8 64 3 1 1 0 0
0000000003d90000 00001002 64 8 64 3 1 1 0 0
0000000003ee0000 00001002 64 16 64 11 1 1 0 0
-------------------------------------------------------------------------------------
Ответы
Ответ 1
Недавно у меня была очень похожая ситуация, и я нашел пару методов, полезных в расследовании. Ни один из них не является серебряной пулей, но каждый из них немного освещает проблему.
1) vmmap.exe от SysInternals (http://technet.microsoft.com/en-us/sysinternals/dd535533) отлично справляется с корреляцией информации о собственной и управляемой памяти и представляет ее в приятном пользовательском интерфейсе. Та же информация может быть собрана с использованием нижеприведенных методов, но это проще и приятное место для начала. К сожалению, он не работает в файлах дампа, вам нужен живой процесс.
2) Выход "! address -summary" представляет собой свертку более подробного вывода "! address". Я счел полезным отбросить подробный вывод в Excel и запустить несколько опорных точек. Используя этот метод, я обнаружил, что большое количество байтов, которые были указаны как "", были фактически страницами MEM_IMAGE, вероятными копиями страниц данных, которые были загружены при загрузке DLL, но затем скопированы, когда данные были изменены. Я мог бы также фильтровать большие регионы и заниматься специальными адресами. Пытаться в дампе памяти с зубочисткой, и много молитвы болезненно, но может быть откровением.
3) Наконец, я сделал неудачную версию техники vmmap.exe выше. Я загрузил файл дампа, открыл журнал и запускал! Адрес,! Eeheap,! Heap и! Threads. Я также нацелил блоки среды потока, перечисленные в ~ * k, с помощью! Teb. Я закрыл файл журнала и загрузил его в свой любимый редактор. Затем я мог бы найти неклассифицированный блок и выполнить поиск, чтобы увидеть, появилось ли оно на выходе из одной из более подробных команд. Вы можете быстро скоррелировать родные и управляемые кучи, чтобы сорвать их из ваших подозрительных неклассифицированных регионов.
Все это слишком ручно. Я хотел бы написать script, который будет выводить результат, аналогичный тому, что я создал в технике 3 выше, и вывести файл mmp, подходящий для просмотра файла vmmap.exe. Когда-нибудь.
Последнее примечание: я сделал корреляцию между выходом vmmap.exe с выходом адреса и отметил эти типы регионов, которые vmmap пары идентифицируют из разных источников (подобно тому, как это используется! heap и! eeheap), но этот адрес didn Не знаю. То есть, это вещи, которые vmmap.exe помечены, но адрес не был:
.data
.pdata
.rdata
.text
64-bit thread stack
Domain 1
Domain 1 High Frequency Heap
Domain 1 JIT Code Heap
Domain 1 Low Frequency Heap
Domain 1 Virtual Call Stub
Domain 1 Virtual Call Stub Lookup Heap
Domain 1 Virtual Call Stub Resolve Heap
GC
Large Object Heap
Native heaps
Thread Environment Blocks
По-прежнему было много неучтенных "private" байтов, но опять же, я могу сузить проблему, если я могу сорвать их.
Надеюсь, это даст вам некоторые идеи о том, как исследовать. Я в одной лодке, поэтому я буду благодарен за то, что вы найдете. Спасибо!
Ответ 2
"Резюме использования" говорит, что у вас есть 3696 регионов без классификации, в общей сложности 17,33 ГБ
"Самый большой регион" сообщает, что самый большой из неклассифицированных регионов - 242 Мб.
Остальная часть неклассифицированных (3695 регионов) вместе составляет разницу до 17,33 ГБ.
Попробуйте сделать кучу -s и подведите итог Virt col, чтобы увидеть размер родной кучи, я думаю, что они также попадают в неуправляемое ведро. (NB более ранние версии показывают, что куча явных явных из! Address -summary)
Ответ 3
Лучше всего было бы использовать команды EEHeap и GCHandles в windbg (http://msdn.microsoft.com/en-us/library/bb190764.aspx) и попытаться выяснить, можете ли вы найти то, что может быть утечкой/неправильным.
К сожалению, вы, вероятно, не сможете получить точную помощь, которую вы ищете, из-за того, что диагностика этих типов проблем почти всегда очень трудоемка, и за пределами простейших случаев требуется, чтобы кто-то выполнял полный анализ на свалке. В принципе маловероятно, что кто-то сможет указать вам на прямой ответ на переполнение стека. В основном люди смогут указать вам команды, которые могут быть полезны. Вам нужно будет много сделать, чтобы узнать больше о том, что происходит.
Ответ 4
Я сохраняю копию инструментов отладки для Windows 6.11.1.404, которая, похоже, может отображать что-то более значимое для "неклассифицированного"
С этой версией я вижу список TEB-адресов, а затем:
0:000> !address -summary
--------- PEB fffde000 not found ----
TEB fffdd000 in range fffdb000 fffde000
TEB fffda000 in range fffd8000 fffdb000
...snip...
TEB fe01c000 in range fe01a000 fe01d000
ProcessParametrs 002c15e0 in range 002c0000 003c0000
Environment 002c0810 in range 002c0000 003c0000
-------------------- Usage SUMMARY --------------------------
TotSize ( KB) Pct(Tots) Pct(Busy) Usage
41f08000 ( 1080352) : 25.76% 34.88% : RegionUsageIsVAD
42ecf000 ( 1096508) : 26.14% 00.00% : RegionUsageFree
5c21000 ( 94340) : 02.25% 03.05% : RegionUsageImage
c900000 ( 205824) : 04.91% 06.64% : RegionUsageStack
0 ( 0) : 00.00% 00.00% : RegionUsageTeb
68cf8000 ( 1717216) : 40.94% 55.43% : RegionUsageHeap
0 ( 0) : 00.00% 00.00% : RegionUsagePageHeap
0 ( 0) : 00.00% 00.00% : RegionUsagePeb
0 ( 0) : 00.00% 00.00% : RegionUsageProcessParametrs
0 ( 0) : 00.00% 00.00% : RegionUsageEnvironmentBlock
Tot: ffff0000 (4194240 KB) Busy: bd121000 (3097732 KB)
-------------------- Type SUMMARY --------------------------
TotSize ( KB) Pct(Tots) Usage
42ecf000 ( 1096508) : 26.14% : <free>
5e6e000 ( 96696) : 02.31% : MEM_IMAGE
28ed000 ( 41908) : 01.00% : MEM_MAPPED
b49c6000 ( 2959128) : 70.55% : MEM_PRIVATE
-------------------- State SUMMARY --------------------------
TotSize ( KB) Pct(Tots) Usage
9b4d1000 ( 2544452) : 60.67% : MEM_COMMIT
42ecf000 ( 1096508) : 26.14% : MEM_FREE
21c50000 ( 553280) : 13.19% : MEM_RESERVE
Largest free region: Base bc480000 - Size 38e10000 (931904 KB)
С моей "текущей" версией (6.12.2.633) я получаю это из того же дампа. Две вещи, которые я отмечаю:
Данные, по-видимому, являются суммой HeapAlloc/RegionUsageHeap и VirtualAlloc/RegionUsageIsVAD).
Прекрасная ошибка EFAIL, которая, без сомнения, частично ответственна за недостающие данные!
Я не уверен, как это поможет вам с вашим управляемым кодом, но я думаю, что он действительно отвечает на исходный вопрос: -)
0:000> !address -summary
Failed to map Heaps (error 80004005)
--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
<unclassified> 7171 aab21000 ( 2.667 Gb) 90.28% 66.68%
Free 637 42ecf000 ( 1.046 Gb) 26.14%
Stack 603 c900000 ( 201.000 Mb) 6.64% 4.91%
Image 636 5c21000 ( 92.129 Mb) 3.05% 2.25%
TEB 201 c9000 ( 804.000 kb) 0.03% 0.02%
ActivationContextData 14 11000 ( 68.000 kb) 0.00% 0.00%
CsrSharedMemory 1 5000 ( 20.000 kb) 0.00% 0.00%
--- Type Summary (for busy) ------ RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_PRIVATE 7921 b49c6000 ( 2.822 Gb) 95.53% 70.55%
MEM_IMAGE 665 5e6e000 ( 94.430 Mb) 3.12% 2.31%
MEM_MAPPED 40 28ed000 ( 40.926 Mb) 1.35% 1.00%
--- State Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
MEM_COMMIT 5734 9b4d1000 ( 2.427 Gb) 82.14% 60.67%
MEM_FREE 637 42ecf000 ( 1.046 Gb) 26.14%
MEM_RESERVE 2892 21c50000 ( 540.313 Mb) 17.86% 13.19%
--- Protect Summary (for commit) - RgnCount ----------- Total Size -------- %ofBusy %ofTotal
PAGE_READWRITE 4805 942bd000 ( 2.315 Gb) 78.37% 57.88%
PAGE_READONLY 215 3cbb000 ( 60.730 Mb) 2.01% 1.48%
PAGE_EXECUTE_READ 78 2477000 ( 36.465 Mb) 1.21% 0.89%
PAGE_WRITECOPY 74 75b000 ( 7.355 Mb) 0.24% 0.18%
PAGE_READWRITE|PAGE_GUARD 402 3d6000 ( 3.836 Mb) 0.13% 0.09%
PAGE_EXECUTE_READWRITE 80 3b0000 ( 3.688 Mb) 0.12% 0.09%
PAGE_EXECUTE_WRITECOPY 80 201000 ( 2.004 Mb) 0.07% 0.05%
--- Largest Region by Usage ----------- Base Address -------- Region Size ----------
<unclassified> 786000 17d9000 ( 23.848 Mb)
Free bc480000 38e10000 ( 910.063 Mb)
Stack 6f90000 fd000 (1012.000 kb)
Image 3c3c000 ebe000 ( 14.742 Mb)
TEB fdf8f000 1000 ( 4.000 kb)
ActivationContextData 190000 4000 ( 16.000 kb)
CsrSharedMemory 7efe0000 5000 ( 20.000 kb)
Ответ 5
Недавно я потратил некоторое время на диагностику проблемы с клиентами, когда их приложение использовало 70 ГБ перед прекращением (вероятно, из-за того, что удалил лимит утилизации пула приложений IIS, но все еще не подтвержден). Они прислали мне дамп памяти на 35 ГБ. Основываясь на моем недавнем опыте, вот несколько замечаний, которые я могу сделать о том, что вы предоставили:
В выводе! heap -s в столбце Commit отображается 284 МБ 1.247 ГБ. Если вы откроете этот дамп в DebugDiag, он скажет вам, что куча 0x60000 имеет 1 ГБ памяти. Вы добавите размер фиксации из 11 сегментов и обнаружите, что они составляют всего около 102 МБ, а не 1 ГБ. Так раздражает.
Недопустимая память отсутствует. На самом деле он намекнул на вывод "heap -s" как строки "Виртуальный блок:". К сожалению,! Heap -s сосет и не показывает конечный адрес должным образом и поэтому сообщает размер как 0. Проверьте вывод следующих команд:
!address 17e0000
!address 45bd0000
!address 6fff0000
Он сообщит о надлежащем конечном адресе и, следовательно, точном "Размер региона". Еще лучше, это дает краткий вариант размера региона. Если вы добавите размер этих трех регионов на 102 МБ, вы должны быть близки к 1 ГБ.
И что в них? Ну, вы можете посмотреть, используя dq. Благодаря spelunking вы можете найти намек на то, почему они были выделены. Возможно, ваш управляемый код вызывает некоторый сторонний код, который имеет собственную сторону.
Вы можете найти ссылки на свою кучу, используя !heap 6fff0000 -x -v
. Если есть ссылки, вы можете видеть, в каких регионах памяти они живут, используя адрес снова. В моей проблеме с клиентами я нашел ссылку, которая жила в регионе с "Usage: Stack". "Дополнительная информация:" подсказка указала на поток стека, в котором оказалось несколько больших вызовов append/copy basic_string вверху.