Статья для понимания всех сборщиков мусора JVM, от Serial до ZGC

JVM алгоритм CMS

«Алгоритмы поиска объектов и алгоритмы повторного использования»Представлен базовый алгоритм сборки мусора, эквивалентный методологии сборки мусора. Далее мы подробно рассмотрим конкретную реализацию сборки мусора.

Как было сказано выше, современные коммерческие виртуальные машины собираются по генерации, и в разных регионах используются разные сборщики. 7 наиболее часто используемых коллекторов, и область их применения показана на рисунке.

Для нового поколения используются Serial, ParNew, Parallel Scavenge;
CMS, Serial Old, Parallel Old используются на старости лет. И они используются в относительно фиксированной комбинации друг с другом (конкретная связь комбинации показана на рисунке выше). G1 является независимым коллектором и не зависит от остальных 6 коллекторов. ZGC является текущим экспериментальным сборщиком для JDK 11.

Рассмотрим характеристики каждого коллектора.

Серийный коллекционер

Serial, является однопоточным для выполнения сборки мусора. Когда приходит время выполнять сборку мусора, программа приостанавливает всю работу, а затем выполняет сборку мусора в одном потоке.

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

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

Коллекционер ParNew

В новом поколении также используется ParNew, это многопоточная версия Serial, полностью аналогичная Serial по параметрам и алгоритмам (в том числе алгоритмам репликации).

Par — это сокращение от Parallel, но его параллелизм относится только к набору многопоточного параллелизма, а не к тому, что набор и исходная программа могут выполняться параллельно. ParNew также необходимо приостановить всю работу программы, а затем в многопоточном режиме выполнить сборку мусора.

Из-за многопоточного выполнения ParNew обычно лучше, чем Serial, на нескольких процессорах. Но если это один процессор, производительность будет хуже из-за переключения потоков.

Параллельный сборщик мусора

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

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

Сборщик Parallel Scavenge предоставляет два параметра для управления выполнением сборки мусора:

  • -XX:MaxGCPauseMillis, максимальное время приостановки сборки мусора. Принцип этого параметра заключается в изменении пространства на время, и коллектор будет контролировать размер области нового поколения, чтобы гарантировать, что восстановление будет меньше, чем это максимальное время паузы, насколько это возможно. Проще говоря, чем меньше площадь утилизации, тем меньше времени на это уходит.
    Таким образом, этот параметр не устанавливается как можно меньше. Если он установлен слишком маленьким, пространство нового поколения будет слишком маленьким, что приведет к более частому запуску GC.
  • -XX:GCTimeRatio, отношение времени сборки мусора к общему времени. Это обратная пропускная способность, и принцип такой же, как у MaxGCPauseMillis.

Поскольку сборщик Parallel Scavenge фокусируется на пропускной способности, при заданных выше параметрах не требуется устанавливать размер каждой области (новое поколение, старое поколение и т. д.). Вы можете включить параметр **-XX:UseAdaptiveSizePolicy**, чтобы позволить JVM отслеживать производительность коллекции и динамически корректировать параметры размера области.

Серийный Старый коллекционер

Сборщик старого поколения однопоточный как Serial, но алгоритм использует Mark-Compact.

Поскольку вероятность выживания объектов в старости высока, если алгоритм репликации все еще используется, необходимо копировать больше контента, а производительность низкая. А в крайнем случае, когда приживаемость 100%, нет возможности использовать алгоритм репликации. Поэтому вам нужно использовать Mark-Compact, чтобы эффективно избежать этих проблем.

Параллельный Старый коллектор

The Old Age Collector — это старая версия Parallel Scavenge. Алгоритм в нем заменен на Mark-Compact.

Сборщик CMS

CMS, Concurrent Mark Sweep, тоже старый коллекционер. Он ориентирован на кратчайшее время паузы для сборки мусора (low pause), что более применимо в сценариях, где у старого поколения нет частого GC.

Именование является параллельным, а не параллельным, что указывает на то, что сборщик может выполняться одновременно с работой. MS указывает, что алгоритм использует алгоритм Mark Sweep.

Давайте посмотрим, как это работает. Весь процесс CMS сложнее, чем у предыдущего сборщика, и весь процесс разбит на четыре шага:

  • Начальная маркировка, однопоточное выполнение, требует «Остановить мир», но отмечаются только непосредственно связанные и достижимые объекты GC Roots.Поскольку напрямую связанные объекты относительно малы, скорость здесь очень высокая.
  • Параллельная метка (одновременная метка) для объекта начальной метки, помеченного процессом начальной метки, выполняет параллельную отслеживающую метку, в это время другие потоки все еще могут продолжать работу. Время здесь длиннее, но оно не останавливается.
  • Перемаркировка (remark), в процессе параллельной маркировки, так как может быть сгенерирован новый мусор, необходимо в это время произвести ремаркировку вновь сгенерированного мусора. Здесь выполняется параллельная маркировка, которая не синхронна с пользовательским потоком, поэтому это все еще «Остановить мир», и время немного больше, чем начальное время.
  • Параллельная очистка, которая одновременно удаляет ранее отмеченный мусор. Другие пользовательские потоки могут по-прежнему работать без задержек.

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

Из-за вышеперечисленных характеристик CMS очевидны и недостатки.

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

Некоторые люди могут подумать, что раз Mark Sweep вызовет фрагментацию памяти, то почему бы не заменить алгоритм на Mark Compact?

Ответ на самом деле очень прост, потому что, когда выполняется параллельная очистка, если память сортируется по Compact, как можно использовать память, используемую исходным пользовательским потоком? Чтобы гарантировать, что пользовательский поток может продолжать выполняться, предполагается, что ресурсы, на которых он работает, не затрагиваются. Mark Compact больше подходит для использования в сценариях «Останови мир».

коллектор G1

G1, Garbage First, был официально запущен в JDK 1.7 и в то время был самым передовым сборщиком мусора. Можно сказать, что G1 — это максимально улучшенная версия CMS, которая решает проблему фрагментации памяти CMS и увеличивает объем памяти. Хотя процесс похож на CMS, лежащие в его основе принципы совершенно другие.

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

Различия в структуре кучи памяти. Предыдущее поколение коллекторов делится на новое поколение, старое поколение, постоянное поколение и так далее.

G1 делит память на несколько регионов одинакового размера, и каждый регион имеет свои собственные атрибуты поколений, но эти поколения не обязательно должны быть непрерывными.

Такие разделы могут эффективно избежать проблемы фрагментации памяти.

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

Чтобы решить эту проблему, G1 поддерживает запомненный набор для каждого региона, который используется для записи ситуации со ссылками на объекты. Когда происходит GC, он ищется в соответствии со ссылкой на запомненный набор.

Два режима ГХ:

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

Общий процесс выполнения:

  • Начальная метка (initial mark) отмечает объекты, непосредственно связанные с GC Root. Реализация STW (Остановите мир).
  • Параллельная маркировка (concurrent marking), одновременно маркирующая изначально отмеченный объект, в это время пользовательский поток еще может выполняться.
  • Последняя метка (Remark), STW, помечает мусор, созданный в параллельном процессе маркировки.
  • Скрининг и переработка (подсчет и удаление данных в реальном времени), оценка помеченного мусора и сбор мусора в соответствии с режимом GC. Реализация СТЗ.

На уровне региона общий алгоритм смещен в сторону Mark-Compact. Поскольку это Compact, это повлияет на выполнение пользовательских потоков, поэтому на этапе повторного использования требуется выполнение STW.

Удивительный ZGC

В JDK 11 был добавлен экспериментальный ZGC. В среднем на переработку уходит менее 2 миллисекунд. Это сборщик с низкой паузой и высокой степенью параллелизма.

ZGC исполняется одновременно практически везде, за исключением того, что начальная отметка STW. Так что время паузы почти тратится на начальную отметку, которой на самом деле очень мало. Так как же другие этапы могут выполняться одновременно?

ZGC в основном добавляет две новые технологии, одна из которыхЦветной указатель, другойПрочитать Барьер Загрузить Барьер.

Цветной указатель
ZGC использует несколько битов 64-битного указателя для представления Finalizable, Remapped, Marked1 и Marked0 (ZGC поддерживает только 64-битные платформы), чтобы отметить состояние хранения указанной памяти. Это эквивалентно маркировке информации об объекте по указателю объекта. Обратите внимание, что указатели здесь эквивалентны ссылкам в терминологии Java.

Когда эта заостренная память изменится (когда память будет перемещена Компактом), цвет изменится.

Как упоминалось в G1, STW требуется на этапе Compact, иначе это повлияет на выполнение пользовательских потоков. Итак, как решить эту проблему?

Прочитать Барьер Загрузить БарьерБлагодаря наличию заштрихованного указателя, когда программа работает для доступа к объекту, легко узнать состояние хранения объекта в памяти (обращение к объекту через указатель), если запрошенная память заштрихована. Тогда сработает барьер чтения. Барьер чтения обновит указатель и вернет результат.Этот процесс имеет определенную стоимость, чтобы добиться эффекта параллелизма с пользовательским потоком.

Разбираемся в этих двух технологиях вместе, цитируя слова R (RednaxelaFX)

По сравнению с традиционным алгоритмом маркировки объектов, ZGC маркирует указатель и добавляет Load Barrier (барьер чтения) при доступе к указателю.Например, когда объект перемещается GC, цвет указателя будет неправильным, и этот барьер сначала обновит указатель до эффективного адреса, а затем вернет, то есть всегда есть вероятность, что только один объект будет тормозить при чтении, и нет Stop The World, чтобы сохранить согласованность приложения с ГК.

Хотя ZGC все еще находится на экспериментальной стадии JDK 11, считается, что в ближайшем будущем он станет основным сборщиком GC из-за значительного улучшения алгоритмов и идей.


Для получения дополнительных технических статей и замечательных сухих товаров, пожалуйста, обратите внимание Блог:zackku.comПубличный аккаунт WeChat: Зак произнес код