Объект пережил несколько молодых сборок, но не был перемещён в старое поколение. Какой механизм JVM объясняет это?
Объект может оставаться в Survivor-регионе, пока его возраст не достигнет текущего порога продвижения (tenuring threshold). JVM может адаптивно изменять этот порог, поэтому нескольких пережитых молодых сборок недостаточно, чтобы гарантировать переход объекта в старое поколение.
Такой подход основан на гипотезе поколений: большинство объектов живёт недолго, поэтому новые объекты выгодно собирать отдельно от долгоживущих. Это уменьшает объём работы сборщика и позволяет не сканировать весь heap при каждой молодой сборке.
Для реализации идеи JVM использует области или регионы для новых объектов, пространств Survivor и старого поколения. Однако конкретная схема зависит от сборщика: например, G1 работает с регионами, а не с фиксированными непрерывными областями поколений.
Если объект переживает молодые сборки, но слишком рано продвигается в старое поколение, он может увеличить нагрузку на последующие старые сборки. Это особенно неприятно для объектов, которые живут немного дольше типичного временного объекта, но затем массово становятся недостижимыми.
Обратная ситуация тоже возможна: при переполнении Survivor-пространств объект может быть продвинут раньше порога возраста. Поэтому возраст является важным ориентиром, но не единственным условием продвижения.
После молодой сборки оставшиеся объекты обычно копируются между областями Survivor. Их возраст увеличивается, а JVM сравнивает его с текущим tenuring threshold. Если порог достигнут, объект продвигается в старое поколение; если нет, он может остаться в Survivor-пространстве.
Порог не обязательно постоянен. JVM может адаптировать его по заполненности Survivor-пространств и распределению возрастов объектов. Такая адаптация помогает использовать Survivor-память эффективнее, но делает поведение зависимым от текущей нагрузки.
Продвижение возможно и раньше порога. Например, если подходящее Survivor-пространство заполнено, JVM может переместить часть объектов в старое поколение, чтобы завершить сборку. У некоторых сборщиков крупные объекты также обрабатываются по специальным правилам; в G1 очень крупный объект может сразу занять специальные humongous-регионы, минуя обычный путь через Survivor.
Следовательно, проверять нужно не только число пережитых сборок. В диагностике полезно сопоставлять логи GC, размеры Survivor-пространств, возрастные гистограммы и объём продвижения в старое поколение. Параметры настройки конкретного сборщика нельзя механически переносить между разными версиями JVM и алгоритмами GC.
Сервис обрабатывал сообщения пакетами. Временные объекты жили дольше одной молодой сборки, но обычно становились недостижимыми после завершения обработки пакета. При резком росте размера пакета Survivor-пространства переполнялись, и значительная часть объектов досрочно продвигалась в старое поколение.
Рассматривались два варианта. Увеличение heap давало запас по памяти, но не устраняло сам факт преждевременного продвижения. Увеличение Survivor-пространств снижало давление на них, однако уменьшало объём памяти, доступный Eden, и могло увеличить частоту молодых сборок.
Выбрали настройку размера Survivor-пространств вместе с изменением размера пакета и проверкой результата по логам GC. Это снизило объём досрочного продвижения без простого наращивания heap; итоговое решение подтвердили измерениями пауз и частоты старых сборок.
Нет. Порог возраста — обычное условие, но не абсолютная гарантия. При нехватке места в Survivor-пространствах объект может быть продвинут раньше, иначе молодая сборка не сможет сохранить все оставшиеся объекты.
Нет. Поведение зависит от выбранного сборщика, версии JVM, размера heap и адаптивных решений во время работы. Даже при одинаковых начальных параметрах фактический порог может измениться под воздействием профиля аллокаций.
Не всегда. Возраст обычно отражает продвижение объекта через циклы обработки молодого поколения, но детали зависят от реализации сборщика. Досрочное продвижение, особенности регионов G1 и специальные правила для крупных объектов могут нарушить простую интерпретацию возраста как точного счётчика сборок.