Ответ 1
Общая проблема
Попытка подсчета и отчета об использовании памяти была обработана таким образом, что в 10 000 раз больше памяти, чем измеряемый размер объекта объекта GC.
Кроме того, печать кол-ва ссылок не применима к проблеме (поскольку в тесте не было открыто/закрыто дескрипторов), но это привело к значительному распределению памяти (удаление только этого счета сократило общие ассигнования в половина).
Исходная программа пыталась измерить выделение 60-120 байт объектов (в зависимости от того, была ли она 32 или 64-разрядной программой), но она делала это с использованием функций, которые вызывали выделение 600 КБ памяти каждый раз, когда они были, половина из которых находилась в куче больших объектов (LOH).
Предлагается альтернативный способ тестирования, который показывает, что все объекты действительно исчезли после вызова GC.Collect. Также приводятся сведения об использовании памяти в функции DisplayMemory.
Заключение
Размер управляемой памяти не увеличивается, когда создаются и собираются объекты 100k. Частные байты процесса увеличиваются примерно на 12 КБ, когда создаются и собираются только 5 объектов, но SoS показывает, что это не из управляемой кучи. Когда вы имеете дело с очень маленькими размерами и количеством объектов, вы не сможете точно определить, что происходит; вместо этого я предлагаю тестирование с очень большим количеством объектов, так что будет очень легко увидеть, что что-то просачивается. В этом случае нет утечки, ничего не получается, все в порядке.
Инструменты и подход анализа
Я использовал два инструмента для просмотра использования памяти этой программой:
- VS 2013 Pro - инструмент для повышения производительности и диагностики. Сначала я запустил эту программу и увидел, что исходная программа выделяет 3,6 МБ памяти, а не только 60-120 байт, как и ожидалось от распределения объектов. Я знал, что какая-то память будет использоваться струнами и записываться на консоль, но 3,6 МБ был шоком.
- Son of Strike (SoS) - это расширение отладчика, которое работает в Visual Studio и WinDbg, и оно поставляется с .Net Framework (см. файл sos.dll в каждом каталоге версий фреймворка на вашем компьютере).
VS 2013 Pro - Инструмент для повышения производительности и диагностики - Примечания
Ниже приведены результаты выполнения исходной программы в инструменте "Производительность и диагностика" в VS 2013 Pro с "методом профилирования", установленным в "Распределение памяти .NET". Это очень быстро подсказывало, что выделяется больше памяти, чем мысли. См. 3,6 МБ общих распределений над диаграммой. Если вы удалите вызовы DisplayMemory, которые упадут до 2476 байт.
Сын забастовки - Примечания
Вы можете использовать SoS в VS2010, если вы не установили .Net 4.5 на машине, или можете использовать его в VS2012 с Update3; просто убедитесь, что вы включили неуправляемую отладку в своем проекте и убедитесь, что вы запускаете 32-битный процесс, а затем запустите ".load sos" в окне "Немедленное окно" отладчика VS. Команды, которые я использовал для просмотра этой проблемы, были: "! Eeheap -gc" и "! Dumpheap -stat".
Альтернативная тестовая программа
class Program
{
static void Main()
{
// A few objects get released by the initial GC.Collect call - the count drops from 108 to 94 objects in one test
GC.Collect();
// Set a breakpoint here, run these two sos commands:
// !eeheap -gc
// !dumpheap -stat
for (int i = 0; i < 100000; i++)
{
object o = new object();
}
// Set a breakpoint here, run these two sos commands before this line, then step over and run them again
// !eeheap -gc
// !dumpheap -stat
GC.Collect();
}
}
Альтернативные результаты испытаний
Резюме
После выделения и сбора 100 000 System.Objects мы заканчиваем на 4 объекта меньше, чем мы начали, и размер управляемой кучи, который на 900 байт меньше, чем мы начали.
Сбор мусора работает должным образом.
Исходный уровень - после первого GC.Collect
!eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x024f23d0
generation 1 starts at 0x024f100c
generation 2 starts at 0x024f1000
ephemeral segment allocation context: none
segment begin allocated size
024f0000 024f1000 024f23dc 0x13dc(5084)
Large object heap starts at 0x034f1000
segment begin allocated size
034f0000 034f1000 034f5380 0x4380(17280)
Total Size: Size: 0x575c (22364) bytes.
------------------------------
GC Heap Size: Size: 0x575c (22364) bytes.
!dumpheap -stat
Statistics:
MT Count TotalSize Class Name
[...]
6ed026b8 1 112 System.AppDomain
6ed025b0 2 168 System.Threading.ThreadAbortException
6ed05d3c 1 284 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[System.Security.Policy.EvidenceTypeDescriptor, mscorlib]][]
6ed03a6c 2 380 System.Int32[]
6ed0349c 20 560 System.RuntimeType
0047fab8 14 1024 Free
6ed02248 32 1692 System.String
6ecefe88 6 17340 System.Object[]
Total 95 objects
После выделения 100 000 System.Objects, перед окончанием GC.Collect
!eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x024f23d0
generation 1 starts at 0x024f100c
generation 2 starts at 0x024f1000
ephemeral segment allocation context: none
segment begin allocated size
024f0000 024f1000 02617ff4 0x126ff4(1208308)
Large object heap starts at 0x034f1000
segment begin allocated size
034f0000 034f1000 034f5380 0x4380(17280)
Total Size: Size: 0x12b374 (1225588) bytes.
------------------------------
GC Heap Size: Size: 0x12b374 (1225588) bytes.
!dumpheap -stat
Statistics:
MT Count TotalSize Class Name
[...]
6ed024e4 1 84 System.OutOfMemoryException
6ed02390 1 84 System.Exception
6ed026b8 1 112 System.AppDomain
6ed025b0 2 168 System.Threading.ThreadAbortException
6ed05d3c 1 284 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[System.Security.Policy.EvidenceTypeDescriptor, mscorlib]][]
6ed03a6c 2 380 System.Int32[]
6ed0349c 20 560 System.RuntimeType
0047fab8 14 1024 Free
6ed02248 32 1692 System.String
6ecefe88 6 17340 System.Object[]
6ed025e8 100002 1200024 System.Object
Total 100095 objects
После окончательного GC.Collect
!eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x024f2048
generation 1 starts at 0x024f2030
generation 2 starts at 0x024f1000
ephemeral segment allocation context: none
segment begin allocated size
024f0000 024f1000 024f2054 0x1054(4180)
Large object heap starts at 0x034f1000
segment begin allocated size
034f0000 034f1000 034f5380 0x4380(17280)
Total Size: Size: 0x53d4 (21460) bytes.
------------------------------
GC Heap Size: Size: 0x53d4 (21460) bytes.
!dumpheap -stat
Statistics:
MT Count TotalSize Class Name
[...]
6ed024e4 1 84 System.OutOfMemoryException
6ed02390 1 84 System.Exception
6ed026b8 1 112 System.AppDomain
0047fab8 9 118 Free
6ed025b0 2 168 System.Threading.ThreadAbortException
6ed05d3c 1 284 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[System.Security.Policy.EvidenceTypeDescriptor, mscorlib]][]
6ed03a6c 2 380 System.Int32[]
6ed0349c 20 560 System.RuntimeType
6ed02248 32 1692 System.String
6ecefe88 6 17340 System.Object[]
Total 91 objects
Обзор использования памяти функции DisplayMemory
По сравнению с распределением System.Object, DisplayMemory - это зависание памяти. Он создает строки (которые идут в кучу), а функции, которые он вызывает для получения памяти, используют тонны (примерно 600 КБ) самой памяти.
Использование памяти перед вызовом DisplayMemory
!eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x02321018
generation 1 starts at 0x0232100c
generation 2 starts at 0x02321000
ephemeral segment allocation context: none
segment begin allocated size
02320000 02321000 02323ff4 0x2ff4(12276)
Large object heap starts at 0x03321000
segment begin allocated size
03320000 03321000 03325380 0x4380(17280)
Total Size: Size: 0x7374 (29556) bytes.
------------------------------
GC Heap Size: Size: 0x7374 (29556) bytes.
!dumpheap -stat
Statistics:
MT Count TotalSize Class Name
[...]
6ed05d3c 3 468 System.Collections.Generic.Dictionary`2+Entry[[System.Type, mscorlib],[System.Security.Policy.EvidenceTypeDescriptor, mscorlib]][]
6ed0349c 20 560 System.RuntimeType
6ed02248 38 2422 System.String
6ecefe88 6 17340 System.Object[]
Total 102 objects
Использование памяти после вызова DisplayMemory
!eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x023224fc
generation 1 starts at 0x023224f0
generation 2 starts at 0x02321000
ephemeral segment allocation context: none
segment begin allocated size
02320000 02321000 02371ff4 0x50ff4(331764)
Large object heap starts at 0x03321000
segment begin allocated size
03320000 03321000 033653c0 0x443c0(279488)
Total Size: Size: 0x953b4 (611252) bytes.
------------------------------
GC Heap Size: Size: 0x953b4 (611252) bytes.
!dumpheap -stat
Statistics:
MT Count TotalSize Class Name
[...]
6ed02c08 9 954 System.Char[]
006dfac0 17 1090 Free
6ed03aa4 156 1872 System.Int32
6ecffc20 152 3648 System.Collections.ArrayList
6ed05ed4 9 7776 System.Collections.Hashtable+bucket[]
7066e388 152 16416 System.Diagnostics.ProcessInfo
6ed02248 669 20748 System.String
706723e4 152 29184 System.Diagnostics.NtProcessInfoHelper+SystemProcessInformation
6ecefe88 463 48472 System.Object[]
706743a4 2104 75744 System.Diagnostics.ThreadInfo
70666568 2104 151488 System.Diagnostics.NtProcessInfoHelper+SystemThreadInformation
6ed0d640 2 262168 System.Int64[]
Total 6132 objects