Что вызывает сбор мусора gen2?
У меня странная ситуация, которую я пытаюсь выяснить.
Бытие:
Я запускаю свою программу на физическом компьютере с ядрами 16 и 128 ГБ оперативной памяти. Я пытаюсь определить, почему он не использует все доступные ядра, обычно он использует в среднем 20-25% CPU (так что 4-5 ядер из 16). Когда я смотрю на счетчики производительности, они показывают порядка 60-70% времени в коллекции мусора.
Для справки, я использую .NET Framework 4 и TPL (Parallel.ForEach) для потоковой передачи важной части моей программы. Я ограничиваю количество потоков количеством ядер.
Проблема:
Я создавал большое количество объектов, слишком много для сборщика мусора, чтобы эффективно обрабатывать его, и поэтому он потратил большое количество времени на сборщик мусора.
Простой вариант:
Я вводил пул объектов, чтобы уменьшить давление на сборщик мусора. Я буду продолжать объединять объекты для повышения производительности, уже объединяя некоторые объекты с уменьшенной сборкой мусора с 60-70% времени до 45% времени, а моя программа работает на 40% быстрее.
Вопрос о гниении (тот, на который я надеюсь, что вы ответите мне):
Моя программа при работе использует не более 14 ГБ доступной ОЗУ, по сравнению с 128 ГБ ОЗУ, это довольно мало. На этом компьютере ничего не работает (это просто тестовый стенд для меня), и доступно много оперативной памяти.
- Если доступно большое количество оперативной памяти, почему вообще существуют какие-либо gen2 (или полные) коллекции? Существует довольно большое количество этих коллекций gen2 (в тысячах). т.е. как определить порог для запуска коллекции gen2?
- Почему сборщик мусора просто не задерживает какие-либо полные коллекции, пока давление на физическое ОЗУ не достигнет более высокого порога?
- Есть ли способ настроить сборщик мусора для ожидания более высокого порога? (т.е. не собирать вообще, если нет необходимости)
EDIT:
Я уже использую возможность использовать сборщик мусора сервера... мне нужно знать, что вызывает генерацию коллекции gen2, а не то, что сборщик мусора сервера лучше (я уже это знаю).
Ответы
Ответ 1
Как я помню, GC клиента по умолчанию. Мой опыт в этом заключается в том, что он не позволяет куче получить очень большой до сбора. Для моих приложений с большой нагрузкой я использую GC сервера.
Вы включаете GC сервера в файл конфигурации приложения:
<?xml version ="1.0"?>
<configuration>
<runtime>
<gcServer enabled="true"/>
</runtime>
</configuration>
Это делает огромную разницу в производительности для меня. Например, одна из моих программ тратила 80% времени на сбор мусора. Включение GC сервера снизилось до чуть более 10%. Использование памяти увеличилось, потому что GC отпустил ее, но это прекрасно для большинства моих приложений.
Еще одна вещь, которая вызовет сборку Gen 2, - это куча больших объектов. См. CLR Inside Out: Неверная большая куча объектов. В двух словах, если вы превысите порог LOH, это вызовет сборку Gen 2. Если вы выделяете много недолговечных больших объектов (около 85 килобайт), это будет проблемой.
Ответ 2
Из-за неопределенной памяти и чтения: http://msdn.microsoft.com/en-us/library/ee787088.aspx, я думаю, что одним из триггеров Gen 2 GC может быть сегмент Gen 2 заполнение. В статье говорится, что сервер GC использует более крупные сегменты, как уже отмечалось, это, вероятно, важно для вашей производительности.
Наличие машины до тех пор, пока у нее практически нет свободной памяти, будет означать, что на каком-то этапе вы получите один адский GC. Это, вероятно, не идеально. Если ваше время в GC настолько велико, это знак, который вы выделяете слишком много объектов, которые достаточно долго выживают, чтобы пройти мимо генералов 0 и 1, и делать это репетитивно. Если использование памяти вашего приложения не растет со временем, это указывает на то, что эти объекты на самом деле недолговечны, но живут достаточно долго, чтобы выжить в коллекции 0 и 1. Это плохая ситуация - вы выделяете короткоживущий объект, но платите полную стоимость коллекции Gen 2, чтобы очистить его.
Если это случай, у вас есть несколько разных направлений:
- Попытайтесь сделать короткие объекты, собираемые раньше (чтобы они не попали в ген 2, и, следовательно, стоимость GC ниже)
- Попробуйте выделить меньше короткоживущих объектов (так что GCs случаются реже, и у вас есть больше времени, чтобы закончить использование ваших короткоживущих объектов до того, как распределения заставят GC и объекты будут перенесены в более старые поколения).
- Использовать типы назначенных стеком значений вместо ссылочных типов для короткоживущих объектов (если это соответствует вашей цели)
- Если вы знаете, что вам нужен большой кусок этих объектов, объедините их вперёд. Похоже, вы делаете это, но должно быть еще много выделения, чтобы сохранить GC на 45%. Если ваш пул недостаточно велик, выделите больше аванса - как вы говорите, у вас много запасной памяти.
Вероятно, комбинация всех из них будет хорошим решением. Вы должны хорошо понимать, какие объекты вы распределяете, как долго они живут, и как долго они действительно должны жить, чтобы выполнить вашу цель.
GC доволен временными объектами, которые имеют короткое время жизни (как в случае, когда они собираются GC), или долгосрочные/постоянные объекты, которые имеют длительный срок службы. Выделяя множество объектов в середине этих двух категорий, вы получаете боль. Поэтому выделяйте меньше или меняйте сроки их жизни, чтобы они соответствовали их сценарию использования.