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