Обычно сбор инициируется (при любом поколении), когда выполняется одно из следующих условий
- Распределение превышает порог. Я смутно помню, как это было динамично, исходя из текущих потребностей. Кто-нибудь может подтвердить / опровергнуть?
- Недостаточно памяти
- Вызывается через GC.Collect ()
Может быть, я пропускаю другой сценарий, но обычно это так. Первый - это то, что обычно запускает коллекцию, и, учитывая, что собирать G2 (относительно) дороже, чем G0, вы видите их меньше.
Для ответа на вопрос в комментарии:
Каждое поколение имеет порог, который при попадании вызовет сбор. Gen0 может быть 5 МБ, и будет запущен, когда он будет заполнен. После запуска GC, если у вас все еще есть 5 МБ, я думаю, это увеличит лимит. Если этого не произошло, то каждое распределение вызовет сбор, и у вас возникнет проблема. Gen2 может быть 20 Мб (заметьте, я здесь составляю цифры), и там применяется та же логика.
Для примера из учебника давайте рассмотрим простой сценарий.
- Новым приложениям, выделенным объектам, и все помещаются в Gen0 на общую сумму 3 МБ данных. (это не всегда так, но сделайте вид, что это так)
- GC попадает, и 1 МБ из этого перемещается в G1, остальное очищается.
- G0 теперь свободен, а G1 имеет 1 МБ.
- Создается больше объектов, и происходит больше GC. Через некоторое время G1 наполняется, а некоторые перемещаются в G2.
- Объекты остаются там до тех пор, пока не заполнится G2, а затем очищаются , если не используются . Если на объект все еще ссылаются, он будет оставаться в G2, пока не будет очищен .
Полный сбор данных стоит дорого, и я видел, как дни проходили без единого случая. Конечно, это было в системе с> 64 ГБ оперативной памяти, и в этом не было необходимости.