Виртуальная машина Java - GC поколений
Большинство JVM делят кучу на три поколения: the young generation (YG), the old generation (OG) and permanent generation (also called tenured generation). Каковы причины такого мышления?
Эмпирические исследования показали, что большинство созданных объектов имеют очень короткий срок службы -
Источник
https://www.oracle.com
Как вы можете видеть, по мере того, как со временем выделяется все больше и больше объектов, количество оставшихся байтов становится меньше (в целом). У Java-объектов высокий уровень смертности.
Мы рассмотрим простой пример. Класс String в Java неизменен. Это означает, что каждый раз, когда вам нужно изменить содержимое объекта String, вы должны полностью создавать новый объект. Предположим, вы вносите изменения в строку 1000 раз в цикле, как показано в приведенном ниже коде -
String str = “G11 GC”;
for(int i = 0 ; i < 1000; i++) {
str = str + String.valueOf(i);
}
В каждом цикле мы создаем новый строковый объект, и строка, созданная во время предыдущей итерации, становится бесполезной (то есть на нее не ссылаются никакие ссылки). Время жизни этого объекта было всего одной итерацией - они будут собраны сборщиком мусора в кратчайшие сроки. Такие недолговечные объекты хранятся в зоне кучи молодого поколения. Процесс сбора объектов у молодого поколения называется второстепенной сборкой мусора, и он всегда вызывает паузу «остановки мира».
По мере того, как молодое поколение заполняется, сборщик мусора выполняет незначительную сборку мусора. Мертвые объекты отбрасываются, а живые объекты передаются старому поколению. Во время этого процесса потоки приложения останавливаются.
Здесь мы видим преимущества, которые предлагает дизайн такого поколения. Молодое поколение - это лишь небольшая часть кучи, которая быстро пополняется. Но обработка занимает намного меньше времени, чем время, необходимое для обработки всей кучи. Так что паузы «стоп-мир» в этом случае намного короче, хотя и чаще. Мы всегда должны стремиться к тому, чтобы паузы были короче, чем более длинные, даже если они могут быть более частыми. Мы обсудим это подробно в следующих разделах этого руководства.
Молодое поколение разделено на два пространства - eden and survivor space. Объекты, которые уцелели во время сбора Эдема, перемещаются в пространство выживших, а те, кто выжил в пространстве выживших, перемещаются в старое поколение. Молодое поколение уплотняют, пока его собирают.
Поскольку объекты перемещаются в старое поколение, оно в конечном итоге заполняется, и его необходимо собирать и уплотнять. В разных алгоритмах используются разные подходы к этому. Некоторые из них останавливают потоки приложения (что приводит к длительной паузе «останови мир», поскольку старое поколение довольно велико по сравнению с молодым поколением), в то время как некоторые из них делают это одновременно, пока потоки приложения продолжают работать. Этот процесс называется полным сборщиком мусора. Два таких коллекционераCMS and G1.
Давайте теперь подробно проанализируем эти алгоритмы.
Последовательный GC
это GC по умолчанию на машинах клиентского класса (однопроцессорные машины или 32-битная JVM, Windows). Как правило, GC являются сильно многопоточными, а последовательный GC - нет. У него есть один поток для обработки кучи, и он будет останавливать потоки приложения всякий раз, когда он выполняет второстепенный или основной сборщик мусора. Мы можем дать команду JVM использовать этот сборщик мусора, указав флаг:-XX:+UseSerialGC. Если мы хотим, чтобы он использовал какой-то другой алгоритм, укажите имя алгоритма. Обратите внимание, что старое поколение полностью уплотняется во время большой сборки мусора.
Пропускная способность GC
Этот GC используется по умолчанию на 64-битных JVM и многопроцессорных машинах. В отличие от последовательного GC, он использует несколько потоков для обработки молодого и старого поколения. Из-за этого сборщик мусора также называютparallel collector. Мы можем приказать нашей JVM использовать этот сборщик с помощью флага:-XX:+UseParallelOldGC или же -XX:+UseParallelGC(для JDK 8 и новее). Потоки приложения останавливаются, пока выполняется основная или незначительная сборка мусора. Как и серийный коллектор, он полностью уплотняет молодое поколение во время крупного GC.
Сборщик мусора пропускной способности собирает YG и OG. Когда райский уголок заполняется, сборщик выбрасывает из него живые объекты либо в OG, либо в одно из пространств выживших (SS0 и SS1 на диаграмме ниже). Мертвые объекты выбрасываются, чтобы освободить место, которое они занимали.
Перед ГК YG
После GC YG
Во время полного GC сборщик пропускной способности очищает все YG, SS0 и SS1. После операции ОГ содержит только живые объекты. Следует отметить, что оба перечисленных выше сборщика останавливают потоки приложения при обработке кучи. Это означает длительные паузы «остановки мира» во время главного сборщика мусора. Следующие два алгоритма направлены на их устранение за счет дополнительных аппаратных ресурсов -
Сборщик CMS
Это означает «одновременная очистка меток». Его функция заключается в том, что он использует некоторые фоновые потоки для периодического сканирования старого поколения и избавления от мертвых объектов. Но во время второстепенного сборщика мусора потоки приложения останавливаются. Однако паузы совсем небольшие. Это делает CMS сборщиком с малыми паузами.
Этому сборщику требуется дополнительное время ЦП для сканирования кучи при выполнении потоков приложения. Кроме того, фоновые потоки просто собирают кучу и не выполняют никакого уплотнения. Они могут привести к фрагментации кучи. По мере того, как это продолжается, через определенный момент времени CMS остановит все потоки приложения и сожмет кучу с помощью одного потока. Используйте следующие аргументы JVM, чтобы указать JVM использовать сборщик CMS:
“XX:+UseConcMarkSweepGC -XX:+UseParNewGC” в качестве аргументов JVM, чтобы указать ему использовать сборщик CMS.
До GC
После GC
Обратите внимание, что сбор выполняется одновременно.
G1 GC
Этот алгоритм работает путем разделения кучи на несколько областей. Как и сборщик CMS, он останавливает потоки приложения при выполнении второстепенного сборщика мусора и использует фоновые потоки для обработки старого поколения, сохраняя при этом потоки приложения. Поскольку он разделил старое поколение на регионы, он продолжает их уплотнять, перемещая объекты из одного региона в другой. Следовательно, фрагментация минимальна. Вы можете использовать флаг:XX:+UseG1GCчтобы указать вашей JVM использовать этот алгоритм. Как и CMS, ему также требуется больше процессорного времени для обработки кучи и одновременного выполнения потоков приложения.
Этот алгоритм был разработан для обработки больших куч (> 4G), которые разделены на несколько различных регионов. Некоторые из этих регионов составляют молодое поколение, а остальные - старое. YG очищается традиционным способом - все потоки приложений останавливаются и все объекты, которые все еще живы для старого поколения или оставшегося пространства.
Обратите внимание, что все алгоритмы GC делят кучу на YG и OG и используют STWP для очистки YG. Этот процесс обычно очень быстрый.