JDK11 | Часть 7: Сборщик мусора ZGC

Java

1. Введение

Java 11 включает совершенно новый сборщик мусора — ZGC, который был разработан Oracle и обещает очень малое время паузы на многотерабайтных кучах. В этой статье мы представляем мотивацию для разработки нового GC, обзор технологии и некоторые возможности, открываемые ZGC.

Так зачем же нужен новый GC? В конце концов, за последние годы в Java 10 было выпущено четыре сборщика мусора, и почти все они поддаются бесконечной настройке. С другой стороны, G1 был представлен в 2006 году вместе с Hotspot VM. Самый большой инстанс AWS на тот момент имел 1 виртуальный ЦП и 1,7 ГБ памяти, а сегодня AWS с радостью предоставит вам инстанс x1e.32xlarge со 128 виртуальными ЦП и 3904 ГБ памяти. Цели разработки ZGC: поддержка объема памяти на уровне ТБ, малое время паузы (

2. Терминология ГХ

Чтобы понять, как ZGC соответствует существующим сборщикам и как реализован новый GC, нам нужно понять некоторую терминологию. Самая простая сборка мусора включает в себя идентификацию памяти, которая больше не используется, и ее повторное использование. Современные коллекционеры выполняют этот процесс в несколько этапов, которые мы часто описываем следующим образом:

  • Параллелизм: во время работы JVM существуют как потоки приложений, так и потоки сборщика мусора. Параллельные этапы выполняются несколькими потоками gc, т.е. работа gc распределяется между ними. Не зависит от того, должен ли поток GC приостановить поток приложения.

  • Последовательный: последовательный этап выполняется только в одном потоке GC. Как и прежде, не объяснялось, нужно ли потоку GC приостанавливать поток приложения.

  • STW: фаза STW, поток приложения приостанавливается, чтобы сборщик мусора мог выполнять свою работу. Когда приложение приостанавливается из-за GC, это обычно происходит из-за фазы Stop The World.

  • Параллелизм: если этап является параллельным, то поток GC может работать одновременно с потоком приложения. Параллельные этапы сложны, потому что их необходимо обработать до завершения этапа, что может сделать работу недействительной.

  • Инкрементный: если этап является инкрементным, он может выполняться в течение определенного периода времени, а затем завершаться досрочно из-за некоторого условия, например, необходимости выполнить этап gc с более высоким приоритетом, при этом продолжая выполнять продуктивную работу. Дополнительные этапы резко контрастируют с этапами, которые требуют полного завершения.

3. Принцип работы

Теперь, когда мы понимаем свойства различных фаз gc, давайте перейдем к тому, как работает ZGC. Для достижения своих целей ZGC добавила в Hotspot Garbage Collectors две новые технологии: указатели затенения и барьеры чтения.

Указатель затенения

Раскрашивающий указатель — это указатель на информацию, хранящуюся в технологии (или справочник терминов Java). Поскольку на 64-битных платформах (ZGC поддерживает только 64-битные платформы) указатель может обрабатывать больше памяти, некоторые биты могут использоваться для хранения состояния. ZGC ограничит максимальную поддержку кучи 4 ТБ (42 бита), затем будут доступны остальные 22, в настоящее время используется 4: finalizable, remap, mark0 и mark1. Мы объясним их использование позже.

Одна проблема с указателями шейдеров заключается в том, что они требуют дополнительной работы (из-за необходимости маскировать биты информации), когда вам нужно отменить шейдер. Такие платформы, как SPARC, имеют встроенную аппаратную поддержку маскирования указателей, так что это не проблема, в то время как для платформ x86 команда ZGC использует хитрый трюк с несколькими отображениями.

Мультикарта

Чтобы понять, как работает multimap, нам нужно кратко объяснить разницу между виртуальной памятью и физической памятью. Физическая память — это фактическая память, доступная системе, обычно емкость установленных микросхем DRAM. Виртуальная память является абстрактной, а это означает, что приложения имеют собственное представление (обычно изолированной) физической памяти. Операционная система отвечает за поддержание сопоставления между диапазонами виртуальной и физической памяти, и она делает это с помощью таблиц страниц и блока управления памятью процессора (MMU) и буфера преобразования (TLB), который преобразует адрес.

Множественное сопоставление включает сопоставление различных диапазонов виртуальной памяти с одной и той же физической памятью. Так как в дизайне всего одна переназначение, а mark0 и mark1 могут быть равны 1 в любой момент времени, это можно сделать с тремя картами. В исходном коде ZGC есть красивая диаграмма, иллюстрирующая это.

прочитать барьер

Читающий барьер - это кусок кода, который запускается всякий раз, когда поток приложений загружает ссылку из кучи (то есть доступа к не примитивным полем на объекте):

void printName( Person person ) {
    String name = person.name;  // 这里触发读屏障
                                // 因为需要从heap读取引用 
                                // 
    System.out.println(name);   // 这里没有直接触发读屏障
}

В приведенном выше коде String name = person.name обращается к ссылке на человека в куче, а затем загружает ссылку в локальную переменную имени. В этот момент срабатывает барьер чтения. Строка Systemt.out не запускает барьер чтения напрямую, поскольку из кучи не загружаются ссылки (имя является локальной переменной, поэтому ссылки из кучи не загружаются). Но система и снаружи или внутри println могут вызвать другие барьеры чтения.

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

отметка

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

Первая часть цикла GC — маркировка. Маркировка включает в себя поиск и маркировку всех объектов кучи, к которым может получить доступ работающее приложение, другими словами, поиск объектов, которые не являются мусором.

Маркировка ZGC делится на три этапа. Первый этап — STW, где корни GC помечаются как живые объекты. Корни GC аналогичны локальным переменным, через которые можно получить доступ к другим объектам в куче. Объект считается мусором, если к нему нельзя получить доступ, обходя граф объектов, начиная с корней, поэтому приложение также не может получить к нему доступ. Коллекция объектов, доступ к которым осуществляется из корней, называется живой коллекцией. Шаг маркировки корней GC очень короткий, потому что общее количество корней обычно невелико.

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

После завершения обхода следует заключительная, недолговечная фаза «Остановить мир», которая обрабатывает некоторые пограничные случаи (которые мы пока игнорируем), а фаза маркировки завершается после завершения этой фазы.

сброс настроек

Следующая важная часть цикла GC — переезды. Перемещение включает в себя перемещение живых объектов, чтобы освободить часть памяти кучи. Зачем перемещать объекты, а не заполнять промежутки? Некоторые сборщики мусора действительно делают это, но это приводит к печальным последствиям: выделение памяти становится более затратным, потому что, когда необходимо выделить память, распределитель памяти должен найти свободное место, где можно разместить объекты. Напротив, если можно освободить большой кусок памяти, выделение памяти так же просто, как увеличение указателя на объем памяти, необходимый для нового объекта.

ZGC делит кучу на множество страниц, и в начале этой фазы одновременно выбирает набор страниц, которым нужно переместить живые объекты. После выбора набора перемещений происходит пауза Stop The World, когда ZGC перемещает корневые объекты в наборе и сопоставляет их ссылки с новым местоположением. Как и в предыдущем шаге «Остановить мир», время паузы здесь зависит только от количества корней и отношения размера набора перемещений к общему активному набору объекта, который обычно довольно мал. Таким образом, в отличие от многих сборщиков, время паузы увеличивается с размером кучи.

После перемещения корня следующим этапом является параллельное перемещение. На этом этапе поток GC проходит через набор перемещений и перемещает все объекты на страницах, которые он содержит. Если поток приложения пытается загрузить объект до того, как GC переместит его, то поток приложения также может переместить объект, что может быть достигнуто через барьер чтения (срабатывает при загрузке ссылки из кучи), как показано на блок-схеме. :

Это гарантирует, что все ссылки, которые видит приложение, будут обновлены, и приложение не сможет работать с перемещенным объектом одновременно.

Поток GC в конечном итоге переместит все объекты в наборе перемещений, однако ссылки на старые местоположения этих объектов все еще могут быть. Сборщик мусора может пройти по графу объектов и переназначить эти ссылки на новые местоположения, но этот шаг требует больших затрат. Таким образом, этот шаг объединяется со следующей фазой маркировки. При обходе графа объектов во время фазы маркировки следующего цикла GC, если найдена неотображенная ссылка, она повторно отображается, а затем помечается как активная.

обобщать

Попытаться понять характеристики производительности сложных сборщиков мусора, таких как ZGC, в отдельности сложно, но из предыдущих разделов ясно, что почти все паузы, с которыми мы столкнулись, зависели только от размера набора корней GC, а не от размера кучи в реальном времени. Единственным исключением является последняя пауза в фазе маркировки, которая обрабатывает завершение маркировки, но она является добавочной, и если бюджет времени GC превышен, то GC вернется к параллельной маркировке, пока не попытается снова.

3. Производительность

Так как же работает ZGC?

Стефан Карлссон и Пер Лиден привели некоторые цифры в выступлении Jfokus в начале этого года. Пропускная способность ZGC SPECjbb 2015 примерно сопоставима с Parallel GC (оптимизированная пропускная способность), но со средним временем паузы 1 мс и максимальным 4 мс. Напротив, G1 и Parallel имеют много пауз GC более 200 мс.

Однако сборщики мусора — это сложное программное обеспечение, и реальную производительность нельзя вывести из результатов тестов. Мы с нетерпением ждем возможности протестировать ZGC самостоятельно, чтобы увидеть, как его производительность зависит от рабочей нагрузки.

Ссылка на эту статью:Tickets.WeChat.QQ.com/Yes/NA Sister PK SJ6th…

Добро пожаловать, чтобы отсканировать код или выполнить поиск в общедоступной учетной записи «Programmer Guoguo» на WeChat и подписаться на меня, вас ждут сюрпризы~