Интервьюер спросил меня, как сборщик G1 узнает, что вы мусор?

Java
Интервьюер спросил меня, как сборщик G1 узнает, что вы мусор?

Это 36-я оригинальная статья о том, почему технологии

Фотография выше была сделана дома в прошлые выходные. Я буду использовать фотографии, которые я сделал для первых фотографий в будущих статьях. Делитесь жизнью, делитесь технологиями, ха-ха.

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

Недавно я смотрел "Любовь во время холеры", и я не знаю, почему он связан с "Западным путешествием на Запад", так что вы можете видеть отражение на стекле, я смотрю "Западное путешествие в Запад".

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

Ладно, вернемся к статье

Пусть увидит "плавающий мусор"

начальство«Интервьюер: Вы сказали, что знакомы с jvm? Тогда вы говорите об одновременном анализе достижимости»В этой статье в основном рассказывается об алгоритме анализа достижимости jvm.

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

Инкрементные обновления и необработанные снимки.

В статье я писал: Изменение диаграммы отношений объектов приведет к двум ситуациям: одна - "плавающий мусор", а другая - "объект исчезает". В случае высокой вероятности интервьюера больше беспокоит второй случай, потому что второй случай внесет исключения в программу. Далее я сделал динамическую диаграмму для анализа ситуации «исчезновение объекта».

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

Для теплого и информативного хардкорного оригинального автора, такого как я, если вы скажете, что хотите этого, то я обязательно вам его дам.

Вот вам движущаяся картинка "плавающего мусора":

Когда параллельная маркировка завершена, граф объектов выглядит следующим образом:

Ты видишь это. Объекты 7, 8, 4, 11, 10 — плавающий мусор. Поскольку они помечены черным цветом, они избежали этой сборки мусора.

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

Как поступать с новыми объектами во время сборки мусора G1?

Некоторые читатели подняли другие очень наводящие вопросы:

Здравствуйте, брат, почему ваш «Интервьюер: Вы сказали, что знакомы с jvm? Тогда вы говорите об одновременном анализе достижимости» В этой статье в основном решается проблема модификации пользовательского потока на этапе параллельной маркировки, когда поток GC и пользовательский поток выполняются одновременно. эталонная связь устраняется, что приводит к проблеме «исчезновения объекта». G1 решает эту проблему, добавляя к исходному снимку барьер предварительной записи.

Но у меня другой вопрос:Когда пользовательский поток выполняется, он не только изменяет отношение ссылки на объект, но и выделяет новые объекты. Я думаю, что эта ситуация очень распространена. Как G1 находит и обрабатывает эти объекты?

Другими словами, название статьи:Как сборщик G1 узнает, когда эти объекты должны быть помечены как мусор?

Это хороший вопрос, и, на первый взгляд, вы внимательно прочитали статью и имеете собственные мысли. очень хорошо.

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

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

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

Вспоминая 2016 год, когда я только выпустился и в одиночку поехал в Пекин, я провел подряд 9 собеседований в компаниях, и ни одна из них не говорила о jvm (конечно, в то время я имел дело с джуниорами-разработчиками). Сейчас все по-другому.Я не знаю, когда jvm превратился из расширенного вопроса интервью в основной вопрос интервью. Если вы не спросите jvm на этапе интервью, это не будет выглядеть как полноценное интервью.

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

Дело не в том, что статус jvm изменился, а в том, что порог становится все выше и выше.

Ну, фуфло закончилось, теперь поговорим о G1.

Знакомство с Garbage First (G1)

Я не знаю, откуда вы знаете G1, но я впервые узнал о сборщике G1 из книги «Углубленное понимание виртуальной машины Java (2-е издание)» Чжоу Чжимина.

Помню, когда я читал G1 в то время, мне казалось, что это книга с небес.

Поскольку автор представил множество других коллекционеров, прежде чем представить G1, я сначала покажу вам оглавление, а затем вернусь к обзору:

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

Но когда дело доходит до сборщика G1, расположение памяти в куче Java выглядит немного «красивой сукой». Потом это становилось все более и более непонятным, и сцена в это время была примерно такой:

Хотя он по-прежнему сохраняет концепции нового поколения и старого поколения, новое поколение и старое поколение больше не изолированы в региональном отношении.Он делит всю кучу Java на несколько независимых областей одинакового размера, называемых регионами. Новое поколение и старое поколение динамически состоят из областей и могут быть прерывистыми интервалами.

Каждый Регион может играть роль пространства Эдема, пространства Выжившего или пространства старого поколения нового поколения в соответствии с потребностями. Кроме того, в нем есть особый тип области под названием Humongous, который специально используется для хранения больших предметов.

Что означает вышеизложенное? На самом деле картина выглядит очень интуитивно:

Например, для CMS используется следующая структура кучи памяти:

На картинке выше видно, что и молодое поколение, и старое поколение являются логически непрерывными пространствами (но не требуют физической непрерывности).

Куча памяти G1 разделена на несколько регионов одинакового размера, но общее количество регионов составляет около 2048, что по умолчанию равно 2048. Для региона это логически непрерывное пространство, а его размер варьируется от 1 МБ до 32 МБ.

Структура выглядит следующим образом:

Приведенные выше E, S и синий квадрат без букв (который можно понять как старый) ни о чем не говорят.

Но видно, что H — это понятие, которого не было в предыдущих сборщиках мусора, оно означает Humongous, чтоУказывает, что эти регионы хранят огромные объекты (огромные объекты, H-obj). Когда размер вновь созданного объекта превышает половину размера региона, он напрямую размещается в одном или нескольких новых непрерывных регионах и помечается как H.

Если честно, понятие выше уже "бэд стрит", и будет обсуждаться любая статья G1, в том числе и эта статья.

Ни в коем случае, друзья, это введение, и мы должны сначала сказать несколько слов. Как и в случае с Dou Dizhu, может ли ваша первая рука быть прямо вне короля? Нет, вам не нужно приходить сначала один на три, шаг за шагом.

Позвольте мне дать вам маленькое пасхальное яйцо.

Вы обратили внимание на данные, которые я упомянул выше, о 2048 году, в диапазоне от 1 МБ до 32 МБ, откуда эти данные, вы верите мне, когда я это говорю?

Когда во многих статьях говорится о G1, они просто говорятКуча памяти разделена на области одинакового размера, диапазон значений размера региона составляет от 1 МБ до 32 МБ, но нет упоминания о 2048. Позвольте мне спросить вас о происхождении:

Первые данные, которые я нашел, были взяты из приведенной выше статьи, которая является источником 4 в конце статьи:

The goal is to have around 2048 regions for the total heap.

Автором этой статьи является Моника Беквит, можете поискать, она (да, я не ошибаюсь, она девушка) была руководителем группы производительности сборщика мусора Oracle G1, авторитетная.

Второй источник данных — это, конечно же, исходный код, который является более авторитетным:

http://hg.openjdk.java.net/jdk/jdk/file/fa2f93f99dbc/src/hotspot/share/gc/g1/heapRegionBounds.hpp

Вы знаете, что 2048 год важен? Я не думаю, что это имеет значение.

Но еще удивительнее знать! Когда девушка говорит о 2048, она знает только, что это игра, и вы должны сказать ей, что это число также является номером регионов G1 по умолчанию.

Когда дело сделано, одежды нет, а заслуги и слава глубоко спрятаны.

Рабочие этапы G1

Эта часть тоже знакомая часть, но если вытерпите, то скоро дойдёт до той части, где вы кричите: БЛЯДЬ, офигенно.

Как мы все знаем, обычно мы говорим, что процесс сбора G1 делится на следующие четыре шага (Описание следующих четырех шагов взято из «Понимание виртуальной машины Java (3-е издание)».):

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

Поэтому цель этой статьи — дать вам понять конкретный процесс следующих этапов.

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

Если вы все еще не понимаете этого после повторного прочтения, то я не смогу написать эту статью.

Начальная маркировка: Этот этап предназначен только для пометки объектов, с которыми GC Roots может напрямую ассоциироваться, и изменения значения TAMS (Next Top at Mark Start), чтобы при одновременном запуске пользовательской программы на следующем этапе можно было создавать новые объекты в правильный доступный регион. Этап должен приостановить поток, но времени очень мало.

И делается это синхронно при заимствовании Minor GC, поэтому у сборщика G1 фактически нет дополнительных пауз на этом этапе.

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

Когда сканирование графа объектов завершено, объекты, записанные SATB с эталонными изменениями во время параллелизма, обрабатываются повторно.

Окончательная маркировка: Еще одна короткая пауза для пользовательского потока, чтобы обработать несколько последних записей SATB, оставшихся после завершения параллельной фазы.

Восстановление после скрининга (подсчет данных в реальном времени и эвакуация): отвечает за обновление статистических данных регионов, сортировку значения восстановления и стоимости каждого региона и формулирование плана восстановления в соответствии с ожидаемым пользователем временем паузы.

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

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

Хотя выше есть 4 этапа, с точки зрения Бога мы можем разделить его на две части, или с точки зрения всего алгоритма, мы можем разделить его на две части:

1. Глобальная параллельная маркировка: глобальная параллельная маркировка.

2. Пауза эвакуации: на этом этапе происходит копирование некоторых живых объектов в регионе в пустой регион, а затем освобождение исходного пространства региона.

Почему я смею так делить?

Часть причины исходит из этой статьи:

Статья «Garbage-First Garbage Collection» — первая статья о G1, опубликованная Sun lab в 2004 году. Достаточно авторитетно?

В этом документе в разделе 2.3 представлены паузы для эвакуации, а в разделе 2.5 представлена ​​параллельная маркировка.Вот несколько снимков экрана:

Другая часть причины заключается в том, что Big R сказал то же самое (см. ссылки в конце статьи).

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

глобальный флаг параллелизма

Этот раздел отвечает на этот вопрос:Когда пользовательский поток выполняется, он не только изменяет отношения ссылок на объекты, но и выделяет новые объекты.Как G1 находит и обрабатывает эти объекты?

Для ответа на этот вопрос привлекается TAMS. В книге, которую я цитировал ранее, говорится:

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

В этом предложении я могу понять каждое слово, и когда я читаю его вместе, я могу немного попробовать, но я всегда чувствую, что понимаю его, но не понимаю.

Что такое ТАМС? Какой правильный доступный регион? Где в Регионе создается новый объект?

Начнем сначала с бумаги, я подберу ключевые моменты и скажу вам:

1. Есть два растровых изображения.

2. Один называется предыдущим, а другой называется следующим.

3. Предыдущее растровое изображение является последним растровым изображением после завершения фазы параллельной маркировки. (небольшой поворот, будет объяснен позже).

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

5. Когда маркировка завершена, два растровых изображения поменяются ролями.

1. Первая фаза цикла маркировки заключается в очистке следующего растрового изображения.

2. Затем, начальная фаза маркировки, Stop The World (далее STW), направлена ​​на маркировку объектов, с которыми GC Roots может напрямую ассоциироваться. Эта фаза выполняется с помощью Minor GC без дополнительных пауз.

3. Каждый регион содержит два TAMS.

4. Один соответствует отметке предыдущего раунда, а другой соответствует отметке следующего.

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

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

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

Можно предположить, что Bitmap (предыдущий Bitmap) после параллельной метки становится примерно таким:

Белые адреса — это объекты, которые можно переработать, а серые адреса — это объекты, которые нельзя переработать.

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

Растровое изображение и TAMS можно представить следующей картинкой:

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

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

Как работают два Bitmap и два TAMS?

Далее следуйте:

Начальная маркировка

Параллельная маркировка

Окончательная маркировка (окончательная маркировка, также называемая Remark)

Очистка

Проиллюстрированы четыре стадии

Начальная маркировка

Как видно из рисунка, начальная фаза маркировки nextBitmap пуста и не помечает уцелевшие объекты.

Тогда мы снова вернемся к описанию в книге, и я дам вам дословное описание:

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

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

Обновление: приведенное выше предложение неверно, подробности см. По ссылке.

Изменить значение TAMS: чтобы prevTAMS в это время указывал на Bottom, что является начальным значением адреса памяти региона. Пусть в это время nextTAMS указывает на Top. Верх на самом деле является демаркационной точкой между нераспределенной областью и выделенной областью региона.

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

Что означает создание нового объекта в правильном доступном регионе, когда пользовательская программа запускается одновременно на следующем этапе?

Следующая фаза одновременного выполнения программы пользователя относится к фазе параллельной маркировки.

Параллельная маркировка

Сначала посмотрите на описание книги, приведенной выше:

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

Посмотрите еще раз на анимацию:

Выполните анализ достижимости объектов кучи, начиная с GC Roots, рекурсивно просканируйте граф объектов во всей куче и найдите уцелевшие объекты:

Это означает, что на этапе параллельной маркировки поток GC работает между prevTAMS и NextTAMS для анализа достижимости объектов в куче (вспомним «трехцветную маркировку»), а после завершения маркировки NextBitmap имеет соответствующий value (Inside — значение адреса), черный цвет соответствует уцелевшим объектам, а белый — мусорным объектам.

Это позволит найти уцелевший объект.

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

Ответ:Объекты между NextTAMS и Top — это объекты, недавно выделенные пользовательским потоком на этой параллельной фазе маркировки, и они неявно активны.

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

Но ищет ли интервьюер ответ на это предложение? нет.

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

Затем вы рисуете картинку поэтапно, указывая, чтобы показать ему, как работают TAMS и Bitmap.

Кроме того, по поводу того, почему NextTAMS и Top пересекаются, необходимо добавить пояснение: предыдущий этап параллельной маркировки — начальная маркировка. Так как начальная отметка STW, то из динамической диаграммы видно: когда начинается параллельная отметка, то есть когда заканчивается начальная отметка, NextTAMS и Top перекрываются.

NextBitmap заполняется значениями по мере выполнения параллельного процесса разметки. И область между NextTAMS и Top становится все больше и больше, что является новым объектом, выделенным пользовательским потоком во время фазы параллельной маркировки.

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

Перекрывающаяся часть — это часть, которая может вызвать «исчезновение объекта». Для G1 это рабочая часть исходного снимка (STAB) плюс барьер предварительной записи (Pre-Wirte Barrier).

Вот почему в книге говорится: после того, как поток GC просканирует граф объектов, ему необходимо повторно обработать объекты, записанные STAB, которые имеют ссылки на изменения во время параллелизма.

Итоговая оценка (замечание)

В книге сказано следующее:

Окончательная маркировка: еще одна короткая пауза для пользовательского потока для обработки последних нескольких записей SATB, оставшихся после окончания параллельной фазы.

На заключительном этапе маркировки, поскольку это STW, граф, соответствующий этому этапу, представляет собой граф после завершения этапа параллельной маркировки, а именно:

Что означают последние несколько записей SATB, оставшихся после завершения фазы параллелизма обработки?

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

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

Очистка

То, что написано в книге, — это стадия скрининга и переработки. Фактически, он включает в себя фазу очистки и фазу переработки. Здесь мы обсуждаем только этап очистки, а не переработку.

На этом этапе NextBitmap и PrevBitmap меняются местами:

Итак, наш график принимает следующий вид:

Как видите, NextBitmap и PrevBitmap поменялись местами, а NextTAMS и PrevTAMS поменялись местами.

В регионе используемая память, соответствующая белой части растрового изображения, становится светло-серой. Просто размечено, не зачищено.

нужно знать, это:Фаза очистки не копирует объекты

Цитируя ответ Big R для описания этого этапа:

Инвентаризация и сброс состояния маркера. Эта стадия немного похожа на стадию развертки в mark-sweep, но вместо очистки фактических объектов в куче она подсчитывает, сколько объектов помечено как живые в каждом регионе в растровом изображении маркировки. На этом этапе, если вообще будет найден регион без живых объектов, он будет возвращен в список выделяемых регионов целиком.

Ну вот мы и можем заполнить предыдущую картинку:

Затем посмотрите на картинку в документе, вы обнаружите, что мой описанный выше процесс основан на этой картинке для анализа, на картинке показаны две петли, A-B-C, D-E-F. Где процесс E, F является повторением процесса B, C:

Я заставил изображение выше двигаться, пожалуйста, посмотрите внимательнее. Обратите внимание на обмен указателями PrevTAMS, NextTAMS и обмен позициями PrevBitmap и NextBitmap на разных этапах:

Если вы не поняли это один раз, посмотрите еще раз. Глядя на него, лучше анализировать его с помощью длинного изображения и движущегося изображения выше.

Использованная литература:

1.https://max.book118.com/html/2018/0815/7043143036001143.shtm

2.https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/G1GettingStarted/index.html

3.https://www.oracle.com/technetwork/java/javase/tech/g1-intro-jsp-135488.html

4.https://www.infoq.com/articles/G1-One-Garbage-Collector-To-Rule-Them-All/

5.https://hllvm-group.iteye.com/group/topic/44381

6. "Углубленное понимание виртуальной машины Java (третье издание)"

Последнее слово (пожалуйста, обратите внимание)

Эта статья правильная«Интервьюер: Вы сказали, что знакомы с jvm? Тогда вы говорите об одновременном анализе достижимости»Дополнение к этой статье. Если вы не видели его, я предлагаю вам сделать это.

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

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

Я порезал свои глазные яблоки, налитые кровью, и мои глаза почти слепы, вы не обращаете внимания на эту волну?

У меня 4 с половиной уровня по английскому языку Ради правильности статьи я насильно прочитал статью на английском языке Вы не чувствуете себя тронутым?

Смотри, не порти меня, старший брат. Писать статьи очень сложно, и вам нужны положительные отзывы.

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

Спасибо за прочтение, настаиваю на оригинальности, очень приветствую и благодарю за внимание.

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

выше.

Добро пожаловать в публичный аккаунт [почему технология] и настаивайте на выводе оригинальности. Делитесь технологиями, пробуйте жизнь, и я надеюсь, что вы и я вместе добьемся прогресса.