Подтвердить что ты не робот

Что вызывает сбор мусора 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, а не то, что сборщик мусора сервера лучше (я уже это знаю).

4b9b3361

Ответ 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), или долгосрочные/постоянные объекты, которые имеют длительный срок службы. Выделяя множество объектов в середине этих двух категорий, вы получаете боль. Поэтому выделяйте меньше или меняйте сроки их жизни, чтобы они соответствовали их сценарию использования.