Мы разрабатываем довольно большое приложение для Windows Forms. На компьютерах нескольких клиентов часто происходит сбой с исключением OutOfMemory. После получения полного дампа памяти приложения в моменты после исключения (вызов clrdump вызывается из обработчика UnhandledException) я проанализировал его с помощью .NET Memory Profiler и windbg.
Memory Profiler показал только 130 МБ в экземплярах живых объектов. Интересно то, что для многих типов объектов было показано очень большое количество недоступных экземпляров (например, 22000 недоступных экземпляров Byte []). В исходной статистике памяти она составляет 127 МБ во всех кучах для данных (что нормально), но указывает на недоступность 133 МБ в куче второго поколения и 640 МБ в большой куче (не в порядке!).
При анализе дампа с помощью windbg приведенная выше статистика подтверждается:
!dumpheap -stat
..... acceptable object sizes...
79330a00 467216 30638712 System.String
0016d488 4804 221756612 Free
79333470 27089 574278304 System.Byte[]
Приложение использует большое количество коротких буферов в течение времени выполнения, но не пропускает их. Тестирование многих экземпляров Byte [] с помощью! Gcroot заканчивается без корней. Очевидно, что большинство из этих массивов недоступны, как указано профилировщиком памяти.
Просто чтобы убедиться, что все в порядке,! Finalizequeue показывает, что ни один объект не ожидает завершения
generation 0 has 138 finalizable objects (18bd1938->18bd1b60)
generation 1 has 182 finalizable objects (18bd1660->18bd1938)
generation 2 has 75372 finalizable objects (18b87cb0->18bd1660)
Ready for finalization 0 objects (18bd1b60->18bd1b60)
А также проверка трассировки стека потоков собственного финализатора показывает, что она не заблокирована.
В настоящее время я не знаю, как диагностировать, почему сборщик мусора не собирает данные (и я верю, что с удовольствием, так как процесс исчерпал память ..)
edit: Основываясь на вводимых ниже данных, я прочел еще немного о фрагментации кучи больших объектов, и, похоже, это могло быть именно так.
Я видел несколько советов, как распределять большие блоки памяти для данных такого типа (в моем случае это разные байты []) и самостоятельно управлять памятью в этой области, но это кажется довольно хакерским решением, а не Я ожидал бы решить проблему с не столь специальным настольным приложением.
Проблема фрагментации вызвана тем фактом (по крайней мере, так многие люди из Microsoft заявляют в блогах), что объекты на LOH не перемещаются во время существования, что понятно, но кажется логичным, что, как только достигается некоторое давление памяти , например, угроза получения OOM, перемещение должно быть выполнено.
Единственное, что меня беспокоит, прежде чем я полностью верю, что причиной является фрагментация, это то, что так много объектов в LOH не имеют ссылок на gcroot - это потому, что даже для сбора мусора в LOH выполняется только частично?
Я буду рад, что указал мне на любое интересное решение, поскольку на данный момент единственное, что я знаю, - это настраиваемое управление некоторым предварительно выделенным блоком памяти.
Любые идеи приветствуются.
Спасибо.