Алгоритм работы Serial GC, Parrallel GC. Часть 1.
Рассмотрим двух ветеранов по сборке мусора в HotSpot JVM и их особенности.
Как GC очищает память от мусора
Есть несколько алгоритмов очищения мусора, из основных можно выделить два :
- Copying collectors
- Mark-sweep-compact
Copying collectors
Память делится на два участка : from-space и to-space.
Принцип работы таков :
- Создание(allocate) объекта в “from-space” (1,2)
- Когда “from-space” заполнен, запускатеся сборщик мусора (3)
- Приложение приостанавливается (stop-the-world)
- Находятся живые объекты в “from-space” и копируются в “to-space” (4)
- Когда все объекты скопированы в “to-space”, “from-space” полностью очищается (5)
- После “to-space” и “from-space” меняются местами (5)
Минусы подхода:
- From-space и to-space должны быть одинакового размера
- Приложение должно остановиться пока полностью не скопирует живые объекты в новую область памяти
Mark-sweep-compact
Процесс работы можно описать так:
- Создание(allocate) обьекта в памяти (1)
- Запустить GC
- Приложение приостанавливается (stop-the-world)
- Обход дерева для маркировки мертвых обьектов (2)
- Удаление объектов из памяти (3)
- После происходит дефрагментация памяти, то есть сжатие(перенесения) живых объектов в начало (4)
Минусы:
- Приложение останавливается пока происходит сборка мусора
- Время работы зависит от размеров памяти и количества объектов
Сборщики мусора HotSpot VM используют подход “Generational Garbage Collection”. Такой подход позволяет использовать разные алгоритмы для разных этапов(областей памяти) сборки мусора что добавляет эффективности в его работе.
Как я писал в первой статье, опытным путем было замечено что большинство новых объектов быстро становятся мусором, и что количество связей между выжившими объектами и вновь родившимися сводятся к минимуму. Была выдвинута слабая гипотеза(weak generational hypothesis) на которую и опирается “Generational Garbage Collection”.
Serial GC
Serial GC - (последовательный сборщик мусора) это один из первых сборщиков мусора который анонсировала компания Oracle с 1.3 версией Java. Он медленно но уверенно работал в те далекие времена, когда только начинали съемки фильма первой части трилогии “Матрица” и апплеты считалось нормой для web-приложений.
Он очень хорошо проявляет себя в работе с небольшим объемом памяти (100-200 Mb) и в одно-процессорной среде.
Как включить : -XX:+UseSerialGC.
Принцип работы
Принцип сборки мусора основывается на поколениях, и к каждому участку памяти применяется свой алгоритм сборки.
Память разделяется на младшее(Edem, Survivor 0,1) и старшее поколения(Tenured)
Выделяются два этапа сборки мусора :
- minor GC
- major GC (полная)
Новые объекты рождаются в Edem. В определенный момент запускается минорный сборщик мусора который копирует выжавшие объекты в S-0
После очередной сборки мусора, выжившие объекты копируются из Edem и S-0 в S-1, соответственно S-0 становится доступен для выживших объектов.
Другими словами в минорной сборке мусора работает алгоритм “Copying collectors”.
Так же сборщик мусора следит за тем, сколько циклов сборки мусора пережил объект, для того что бы он стал достаточно стар, что бы попасть в Tenured.
После того как Tenured заполнился до определенной критической точки, на ринг выходит major GC, который стирает грань между поколениями(если быть точным то работает с двумя поколениями) и чистит всю память используя алгоритм “Mark-sweep-compact” для старого поколения и “Copying collectors” для молодого.
Плюсы и минусы
Это одно-поточный сборщик мусора, который очень любит stop-the-world(STW) моменты. И работает он с небольшим объемом памяти, так как при увеличении (памяти), STW паузы будут более заметны. Можно сделать вывод что он не прихотлив к ресурсам и спокойно себе пашет в полях операционной среды. Если у вас слабенькая(старенькая) машинка, и не критичны STW паузы, то этот сборщик мусора будет вам очень кстати.
Настройка
Единственное с чем можно поиграться в настройках так это с регулировкой объемов поколений и значением процента заполнения поколений, когда будет срабатывать GC.
- Xms и Xmx можно настроить начальный и максимально допустимый размер кучи.
- -XX:MinHeapFreeRatio=? и -XX:MaxHeapFreeRatio=? задают минимальную и максимальную долю свободного места в каждом поколении, при достижении которой размер поколения будет автоматически увеличен или уменьшен соответственно.
- -XX:NewRatio=? отношение размера старшего поколения к суммарному размеру регионов младшего поколения
- -XX:-UseGCOverheadLimit - порог активности сборщика мусора при котором он будет срабатывать
Parralell GC
Parallel GC (параллельный сборщик) - перенимает идеи Serial GC добавляя в них параллелизм и немного интеллекта. JVM может автоматически задействовать его если на вашем компьютере несколько ядер.
Как включить : -XX:+UseParallelGC.
Принцип работы
При включении параллельного сборщика мусора используются те же самые подходы что и в GC, та же разбивка памяти на Edem, S-0, S-1, Tunered, те же алгоритмы сборки minor cycle и major cycle, но во первых сборка мусора происходит в параллельном режиме, во вторых, добавляется “интеллектуальность” для оптимизации производительности о которой мы поговорим ниже.
Для параллельной обработки объектов, действует немного изменённый механизм переноса. Так например каждый поток GC получает свой участок памяти куда он будет копировать выжившие объекты что бы не мешать другим потокам. Это дает ускорение, но немного дефрагментирует память.
Интеллектуальной составляющей как раз является то, что производительность сборки мусора(так и самого приложения) можно настраивать так, что бы она удовлетворяла ваши потребности. Вы можете указать устраивающие вас параметры производительности — максимальное время сборки и/или пропускную способность — и сборщик будет изо всех сил стараться не превышать заданные пороги. Для этого он будет использовать статистику уже прошедших сборок мусора и исходя из нее планировать параметры дальнейших сборок: варьировать размеры поколений, менять пропорции регионов.
Но это не значет, что GC запрещает нам корректировать размеры поколений самостоятельно, но не рекомендуется это делать одновременно (что бы портить внутреннюю статистику).
Плюсы и минусы
Время STW пауз значительно ниже, так как сборка происходит в параллельном режиме, да и плюс “интеллектуальность” помогает еще больше уменьшить эти паузы (предварительно разогрев JVM). Из минусов можно сказать что появляется фрагментация памяти, но вряд ли она будет значительной, так как сборщиком мусора использует относительно небольшое количество потоков.
Настройка
Размер областей поколений настраивается так же как и Serail GC, поэтому здесь мы рассмотрим настройку производительности для нашего “умного” сборщика мусора.
- -XX:ParallelGCThreads=? - количество потоков для сборки мусора
- -XX:-UseParallelOldGC. - так же можно исключить работу параллельного сборщика мусора в старшем поколении, задействовав однопоточный
- -XX:MaxGCPauseMillis - устанавливает ограничение на максимальное время приостановки программы для сборки мусора
- GCTimeRatio - можно указать желаемый порог пропускной способности (отношения времени работы программы ко времени сборки мусора)
- -XX:YoungGenerationSizeIncrement=? и -XX:TenuredGenerationSizeIncrement=? устанавливают, на сколько процентов следует при необходимости увеличивать младшее и старшее поколение соответственно. По умолчанию оба этих параметра равны 20.
В целом эти два сборщика мусора являются основополагающими и подходят для большинства приложений. Они просты, понятны, без лишних овехэдов и скрытых накладных ресурсов.
В следующей статье мы коснемся более изощренных подходов и механизмов в сборке мусора, таких как CMS GC и G1.