Высокое использование памяти для приложения.Net с большим количеством ручек
Я делаю посмертный анализ в приложении с высокой нагрузкой на память, используя WinDbg с дампом процесса, и этот процесс является службой Windows.
У меня сложилось впечатление, что большая часть 14 ГБ этой памяти используется процессами из прерванных потоков, таким образом, из-за большого количества потерянных семафоров / событий / мутантов и т. Д. Но я не смог собрать все это вместе и сложить их, например, сколько нужно памяти для отдельного семафора /events/mutant и какие команды WinDbg будут полезны для такой ситуации?
Ниже приведен вывод WinDbg:
!справиться
**Type Count**
None 90
Event 5550
Section 41
File 1166
Directory 3
Mutant 160
Semaphore 4581
Key 78
Token 2
Thread 553
IoCompletion 6
Timer 1
TpWorkerFactory 3
ALPC Port 9
WaitCompletionPacket 33
! address -summary
--- Usage Summary ---------------- RgnCount ----------- Total Size -------- %ofBusy %ofTotal
<unknown> 471 3`86ea2000 ( 14.108 Gb) 92.40% 0.01%
! threads(многие из перечисленных потоков имеют исключения ThreadAbortException)
Lock
ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception
12 3 33f0 00000017e3c23200 1282b221 Preemptive 0000000000000000:0000000000000000 00000017e3bb3930 1 MTA System.Threading.ThreadAbortException 000000181de5d668
1 ответ
Ручки и их обертки, скорее всего, довольно маленькие. использование dt -r
чтобы понять их размер:
0:025> dt -r ntdll!_KSEMAPHORE
+0x000 Header : _DISPATCHER_HEADER
+0x000 Type : UChar
+0x001 TimerControlFlags : UChar
+0x001 Absolute : Pos 0, 1 Bit
+0x001 Coalescable : Pos 1, 1 Bit
+0x001 KeepShifting : Pos 2, 1 Bit
+0x001 EncodedTolerableDelay : Pos 3, 5 Bits
+0x001 Abandoned : UChar
+0x001 Signalling : UChar
+0x002 ThreadControlFlags : UChar
+0x002 CpuThrottled : Pos 0, 1 Bit
+0x002 CycleProfiling : Pos 1, 1 Bit
+0x002 CounterProfiling : Pos 2, 1 Bit
+0x002 Reserved : Pos 3, 5 Bits
+0x002 Hand : UChar
+0x002 Size : UChar
+0x003 TimerMiscFlags : UChar
+0x003 Index : Pos 0, 6 Bits
+0x003 Inserted : Pos 6, 1 Bit
+0x003 Expired : Pos 7, 1 Bit
+0x003 DebugActive : UChar
+0x003 ActiveDR7 : Pos 0, 1 Bit
+0x003 Instrumented : Pos 1, 1 Bit
+0x003 Reserved2 : Pos 2, 4 Bits
+0x003 UmsScheduled : Pos 6, 1 Bit
+0x003 UmsPrimary : Pos 7, 1 Bit
+0x003 DpcActive : UChar
+0x000 Lock : Int4B
+0x004 SignalState : Int4B
+0x008 WaitListHead : _LIST_ENTRY
+0x000 Flink : Ptr64 _LIST_ENTRY
+0x008 Blink : Ptr64 _LIST_ENTRY
+0x018 Limit : Int4B
Так что семафор имеет размер 0x18+4 байта. Помните, что размер может увеличиться, если Ptr
детали используются, например, если у вас очень большой список ожидания.
Я рекомендую !dumpheap -stat
в вашей ситуации. Это выведет список объектов.NET, отсортированных по их общему размеру.
Как правило, есть byte[]
, object[]
(или аналогичный) и String
которые едят больше всего памяти.
0:025> !dumpheap -mt 000007feef0aea80
Address MT Size
[...]
000007feef0bda88 4915 329862 System.String
000007feef0be100 1419 382288 System.Object[]
000007feef05f748 2 786520 System.UInt32[]
Total 65575 objects
Для одного объекта вы можете использовать !objsize <address>
, System.Threading.Thread
в моем примере было 16 кБ. Таким образом, даже если у вас 1000 потоков, это просто компенсирует 16 МБ памяти. Пример System.Threading.ManualResetEvent
составляет всего 80 байт в моем приложении.
0:025> !objsize 0000000011878358
sizeof(0000000011878358) = 16736 (0x4160) bytes (System.Threading.Thread)
0:025> !objsize 00000000118af810
sizeof(00000000118af810) = 80 (0x50) bytes (System.Threading.ManualResetEvent)