Карточный стол JVM

JVM

Мы знаем, что когда JVM выполняет сборку мусора, она должна сначала пометить все достижимые объекты, а затем очистить недоступные объекты, чтобы освободить место в памяти. Итак, как быстро найти все доступные объекты?

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

Простые и грубые реализации обычно нежелательны. Так как же JVM обеспечивает быструю маркировку доступных объектов?

Ответ — GC Roots.

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

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

Для HotSpot JVM технология маркировки карт используется для решения проблемы эталона от старого поколения к молодому поколению. В частности, используйте таблицу карточек и барьер записи, чтобы пометить и ускорить сканирование корней GC.

Карточный стол

Основываясь на конструкции карточного стола, пространство кучи обычно делится на серию карточных страниц со степенью двойки.

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

Страница HotSpot JVM-карты (Card Page) размером 512 байт, карточная таблица (Card Table) реализована в виде простого массива байтов, каждая вкладка тега таблицы представляет собой байт.

При записи ссылки на объект (изменении ссылки на объект) логика барьера записи помечает страницу карточки, на которой расположен объект, как грязную.

Логика упрощения маркировки карты по умолчанию для OpenJDK/Oracle 1.6/1.7/1.8 JVM выглядит следующим образом:

CARD_TABLE [this address >> 9] = 0;

Сначала вычислите порядковый номер таблицы карточек страницы карточки, на которой находится ссылка на объект. Сдвиг адреса вправо на 9 бит эквивалентен делению адреса на 512 (2 в 9-й степени). Это можно понять таким образом, предположив, что начальный адрес страницы карты таблицы карт равен 0, тогда начальные адреса страницы карты, соответствующие элементам таблицы карт 0, 1 и 2, равны 0, 512 и 1024 соответственно (номер индекса элемента таблицы карт умножается на страницу карты 512). байт).

Во-вторых, через номер индекса таблицы карт установите соответствующий идентификатор карты как грязный.

2 проблемы

1. Накладные расходы на производительность, вызванные безусловными барьерами записи

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

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

2. Накладные расходы на производительность, вызванные виртуальным совместным использованием при высокой степени параллелизма.

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

Если предположить, что размер строки кэша ЦП составляет 64 байта, поскольку одна запись таблицы карточек занимает 1 байт, это означает, что 64 записи таблицы карточек будут совместно использовать одну и ту же строку кэша.

Каждая страница карты HotSpot занимает 512 байт, поэтому одна строка кэша будет соответствовать 64 страницам карты, всего 64 * 512 = 32 КБ.

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

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

Это решение представлено в JDK 7. Введен новый параметр JVM -XX:+UseCondCardMark.Перед выполнением барьера записи сделайте простое суждение. Если страница карты уже была помечена, она не будет помечена повторно.

Простое понимание заключается в следующем:

if (CARD_TABLE [this address >> 9] != 0)
  CARD_TABLE [this address >> 9] = 0;

По сравнению с исходной реализацией просто добавлена ​​операция суждения.

Хотя после включения -XX:+UseCondCardMark возникают дополнительные накладные расходы, это позволяет избежать проблемы одновременной записи карты, которая может возникнуть в ситуациях с высоким уровнем параллелизма. Сокращение числа одновременных операций записи позволяет избежать ложного совместного использования.

Также используется для CMS GC

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

  • Новое поколение объектов продвигается к старому году;
  • Выделять объекты прямо в старом поколении;
  • Ссылочное отношение объекта старого поколения изменилось;
  • и Т. Д.

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

Смотрите также:7 этапов CMS GC на Java


Ссылаться на

Пан Шийи-лоб в эфире net.blogspot.com/2014/10/Он и…

blogs.Oracle.com/Dave/false-…

bibliography.self language.org/_static/oldtime…

woohoo.memorymanagement.org/glossary/ нет. …

woohoo.memorymanagement.org/glossary/me. …

docs.Oracle.com/Chengdu/E19205-0…

если eve.com/false что Рин...

«Углубленный разбор виртуальной машины Java» Чжэн Юди

Личный публичный аккаунт

Для получения дополнительных статей, пожалуйста, обратите внимание на общедоступный номер: Binary Road

二进制之路