Внутреннее устройство сборщика мусора Garbage-First в Java VM

Размер кучи Java

G1 соблюдает стандартные правила при изменении размера кучи Java, используя -XX:InitialHeapSize в качестве минимального размера кучи Java, -XX:MaxHeapSize в качестве максимального размера кучи Java, -XX:MinHeapFreeRatio для минимального процента свободной памяти, -XX:MaxHeapFreeRatio для определение максимального процента свободной памяти после изменения размера. Сборщик G1 учитывает изменение размера кучи Java только во время пауз Remark и Full GC. Этот процесс может освободить память или выделить ее из операционной системы.

Определение размера фазы "только для молодых"

G1 всегда измеряет молодое поколение в конце нормальной молодой сборки для следующей фазы мутатора. Таким образом, G1 может соответствовать целям времени паузы, которые были установлены с помощью -XX:MaxGCPauseTimeMillis и -XX:PauseTimeIntervalMillis на основе долгосрочных наблюдений фактического времени паузы. Он учитывает, сколько времени потребовалось молодым поколениям того же размера, чтобы эвакуироваться. Это включает в себя информацию о том, сколько объектов нужно было скопировать во время сбора и насколько взаимосвязаны эти объекты.

Если нет других ограничений, то G1 адаптивно определяет размер молодого поколения между значениями, которые -XX:G1NewSizePercent и -XX:G1MaxNewSizePercent определяют для соответствия времени паузы.

В качестве альтернативы -XX:NewSize в сочетании с -XX:MaxNewSize можно использовать для установки минимального и максимального размера молодого поколения соответственно.

Примечание. Указание только одного из этих последних параметров приводит к тому, что размер молодого поколения будет точно соответствовать значению, передаваемому с -XX:NewSize и -XX:MaxNewSize соответственно. Это отключает контроль времени паузы.

Определение размера фазы восстановления пространства

На этапе восстановления пространства G1 пытается максимизировать количество пространства, которое освобождается в старом поколении за одну паузу сбора мусора. Размер молодого поколения установлен на минимально допустимый размер, обычно определяемый -XX:G1NewSizePercent.

В начале каждой смешанной сборки на этом этапе G1 выбирает набор областей из кандидатов набора сбора для добавления в набор сбора. Этот дополнительный набор регионов старого поколения состоит из трех частей:

  • Минимальный набор регионов старого поколения для обеспечения прогресса в эвакуации. Этот набор областей старого поколения определяется числом регионов в наборе кандидатов сбора, деленным на длину фазы восстановления пространства, как определено -XX:G1MixedGCCountTarget.
  • Дополнительные области старого поколения из кандидатов набора сбора, если G1 предсказывает, что после сбора минимального набора останется время. Регионы старого поколения добавляются до тех пор, пока не будет использовано 80% оставшегося времени.
  • Набор необязательных областей набора сбора, который G1 эвакуирует постепенно после того, как другие две части были эвакуированы, и в этой паузе осталось время.

Первые два набора областей собираются на начальном этапе сбора, а дополнительные области из дополнительного набора сбора вписываются в оставшееся время паузы. Этот метод обеспечивает процесс восстановления пространства при одновременном повышении вероятности сохранения времени паузы и минимальных накладных расходов благодаря управлению дополнительным набором сбора.

Фаза восстановления пространства заканчивается, когда оставшийся объем пространства, который может быть освобожден в областях-кандидатах набора сбора, меньше, чем процент, установленный -XX:G1HeapWastePercent.

Периодические сборки мусора

Если сборка мусора в течение долгого времени отсутствует из-за неактивности приложения, виртуальная машина может долго удерживать большой объем неиспользуемой памяти, которую можно было бы использовать в другом месте. Чтобы избежать этого, G1 можно заставить выполнять регулярную сборку мусора с помощью опции -XX:G1PeriodicGCInterval. Эта опция определяет минимальный интервал в мс, с которым G1 рассматривает выполнение сборки мусора. Если это количество времени прошло с момента какой-либо предыдущей паузы при сборке мусора и конкурентный цикл не выполняется, G1 запускает дополнительные сборки мусора со следующими возможными эффектами:

  • На этапе "только для молодых": G1 запускает конкурентную маркировку, используя паузу конкурентного запуска (Concurrent Start pause) или, если было указано -XX:-G1PeriodicGCInvokesConcurrent, полный GC.
  • На этапе восстановления пространства: G1 продолжает этап восстановления пространства, инициируя тип паузы при сборке мусора, соответствующий текущему прогрессу.

Параметр -XX:G1PeriodicGCSystemLoadThreshold может использоваться для уточнения того, запускается ли сборка мусора: если среднее значение загрузки системы за одну минуту, возвращаемое вызовом getloadavg() в хост-системе JVM (например, контейнер), выше этого значения, периодическая сборка мусора не будет запущена.

Определение начального заполнения кучи

Процент начального заполнения кучи (IHOP, Initiating Heap Occupancy Percent) - это порог, при котором запускается сборка Initial Mark, и он определяется как процент от размера старого поколения.

G1 по умолчанию автоматически определяет оптимальный IHOP, наблюдая, сколько времени занимает маркировка и сколько памяти обычно выделяется в старом поколении во время циклов маркировки. Эта функция называется Adaptive IHOP. Если эта функция активна, то параметр -XX:InitiatingHeapOccupancyPercent определяет начальное значение в процентах от размера текущего старого поколения, если не хватает наблюдений, чтобы сделать хороший прогноз порога заполнения для инициирующей кучи. Отключите это поведение G1 с помощью опции -XX:-G1UseAdaptiveIHOP. В этом случае значение -XX:InitiatingHeapOccupancyPercent всегда определяет этот порог.

Внутри Adaptive IHOP пытается установить начальное заполнение кучи так, чтобы первая смешанная сборка мусора фазы восстановления пространства начиналась, когда занятость старого поколения имеет текущий максимальный размер старого поколения минус значение -XX:G1HeapReservePercent в качестве дополнительного буфера.

Маркировка

В маркировке G1 используется алгоритм Snapshot-At-The-Beginning (SATB). Он делает виртуальный снимок кучи во время паузы Initial Mark, когда все объекты, которые были активны в начале маркировки, считаются живыми до конца маркировки. Это означает, что объекты, которые становятся мертвыми (недоступными) во время маркировки, по-прежнему считаются живыми с целью восстановления пространства (за некоторыми исключениями). Это может привести к неправильному сохранению некоторой дополнительной памяти по сравнению с другими сборщиками. Однако SATB потенциально обеспечивает лучшую задержку во время паузы Remark. Слишком консервативно рассматриваемые живые объекты во время этой маркировки будут возвращены во время следующей маркировки.

Поведение в очень трудных ситуациях кучи

Когда приложение сохраняет так много памяти, что эвакуация не может найти достаточно места для копирования, происходит сбой эвакуации. Ошибка эвакуации означает, что G1 пытается завершить текущую сборку мусора, сохраняя все объекты, которые уже были перемещены, в их новом местоположении, и не копируя никакие еще не перемещенные объекты, только настраивая ссылки между объектом. Неудача эвакуации может повлечь за собой некоторые дополнительные издержки, но, как правило, должна быть такой же быстрой, как и у других молодых сборок. После этой сборки мусора с ошибкой эвакуации G1 возобновит работу приложения в обычном режиме без каких-либо других мер. G1 предполагает, что сбой эвакуации произошел ближе к концу сборки мусора; то есть большинство объектов уже были перемещены, и осталось достаточно места для продолжения работы приложения, пока не завершится маркировка и не начнется восстановление пространства.

Если это предположение не выполняется, то G1 в конечном итоге назначит полный сбор мусора (Full GC). Этот тип сбора выполняет сжатие на месте всей кучи. Это может быть очень медленно.

Огромные объекты (Humongous Objects)

Огромные объекты - это объекты, размер которых больше или равен размеру половины региона. Текущий размер региона определяется эргономично, если только он не задан параметром -XX:G1HeapRegionSize.

Эти огромные объекты иногда обрабатываются особым образом:

  • Каждый огромный объект выделяется как последовательность смежных областей в старом поколении. Начало самого объекта всегда находится в начале первой области в этой последовательности. Любое оставшееся пространство в последней области последовательности будет потеряно для выделения, пока весь объект не будет восстановлен.
  • Как правило, огромные объекты могут быть восстановлены только в конце маркировки во время паузы очистки или во время полной сборки мусора (Full GC), если они стали недоступными. Однако существует специальное положение для огромных объектов для массивов примитивных типов, например, bool, всевозможных целых чисел и значений с плавающей запятой. G1 оппортунистически пытается вернуть огромные объекты, если на них не ссылаются многие объекты в любой паузе сборки мусора. Это поведение включено по умолчанию, но вы можете отключить его с помощью опции -XX:G1EagerReclaimHumongousObjects.
  • Распределение огромных объектов может привести к преждевременному прерыванию процесса сбора мусора. G1 проверяет пороговое значение начальной заполняемости кучи при каждом выделении огромных объектов и может немедленно инициировать начальную сборку меток "молодой", если текущая занятость превышает этот порог.
  • Огромные объекты никогда не двигаются, даже во время Full GC. Это может вызвать преждевременные медленные полные сборочные файлы или неожиданные условия нехватки памяти с большим количеством свободного места из-за фрагментации пространства области.

Читайте также:


Комментарии

Популярные сообщения из этого блога

Методы класса Object в Java

Как получить текущий timestamp в Java

Основные опции JVM для повышения производительности и отладки