жареный! Задал мне 18 вопросов JVM за один раз!

JVM
жареный! Задал мне 18 вопросов JVM за один раз!

предисловие

Важность GC для Java очевидна, будь то настройка JVM в будние дни или безжалостная бомбардировка на собеседованиях.

В этой статье я буду расширять содержание GC в формате вопросов и ответов.

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

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

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

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

Хорошо, давайте начнем шоу.

Молодой сборщик мусора, старый сборщик мусора, полный сборщик мусора, смешанный сборщик мусора не различают?

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

Теперь давайте ответим на этот вопрос.

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

Частичный сборщик мусора — это частичный сбор, разделенный на молодой gc, старый gc, смешанный gc.

  • молодой gc: относится к GC, который собирает только молодое поколение.
  • старый сборщик мусора: относится к сборщику мусора, который собирает только старое поколение.
  • смешанный gc: относится к сборщику G1 и относится к GC, который собирает все молодое поколение и часть старого поколения.

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

На самом деле, есть также термин Major GC, В «Углубленном понимании виртуальной машины Java» этот термин относится только к GC старого возраста, что эквивалентно старому GC, но есть также много источников, которые думают это эквивалентно полному gc.

Существует также Minor GC, который относится к GC молодого поколения.

Что является триггерным условием молодого gc?

Можно грубо считать, что молодой gc сработает, когда рай молодого поколения вот-вот наполнится.

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

Например Parallel Scavenge, но есть параметры, которые можно настроить так, чтобы он не выполнял молодой сборщик мусора.

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

Существует два триггерных фактора для заполнения eden: один — недостаточно памяти, выделенной для объектов, а другой — недостаточно памяти, выделенной для TLAB.

Каковы условия срабатывания для полной сборки мусора?

Это условие триггера немного больше, давайте посмотрим.

  • Когда нужно выполнить молодое GC, согласно предыдущей статистике, средний размер продвижения молодого поколения больше, чем оставшееся пространство старого поколения, что вызовет полное GC.
  • Если есть постоянное поколение, если постоянное поколение заполнено, будет запущен полный сборщик мусора.
  • Если места в старом поколении недостаточно, большой объект напрямую подает заявку на выделение в старом поколении.Если в это время места в старом поколении недостаточно, будет запущен полный сборщик мусора.
  • Сбой гарантии означает сбой продвижения, область to нового поколения не может содержать объекты, скопированные из eden и из, или возраст GC объекта нового поколения достигает порогового значения и нуждается в повышении.
  • Выполнение таких команд, как System.gc(), jmap -dump и т. д., приведет к полному сбору мусора.

Знаете о TLAB? давай поговорим

Это должно начаться с приложения памяти.

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

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

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

Поэтому я создал TLAB (Thread Local Allocation Buffer), чтобы применить область выделения памяти для потока.

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

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

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

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

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

Если эта площадь израсходована, вы можете подать заявку снова.

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

А TLAB будет занимать место, давайте посмотрим на эту картинку.

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

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

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

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

Таким образом, в целом TLAB предназначен для предотвращения конфликтов при распределении объектов.

Знает ли это ПЛАБ?

Видно, что он очень похож на TLAB, PLAB — это Promotion Local Allocation Buffers.

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

Когда YGC выполняется параллельно с несколькими потоками, может быть много объектов, которые нужно повысить до старости.В это время указатели старости «горячие», поэтому создается PLAB.

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

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

Это похоже на идею TLAB.

Настоящая причина отказа параллельного режима

«Глубокое понимание виртуальной машины Java»: поскольку сборщик CMS не может обрабатывать «плавающий мусор», может произойти сбой «сбой параллельного режима», и будет создан еще один полный «Остановить мир» полный сборщик мусора.

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

а такжеНа самом деле, Full GC вызвал эту ошибку., давайте взглянем на исходный код, версия openjdk-8.

Сначала найдите эту ошибку.

посмотри сноваreport_concurrent_mode_interruptionкем.

найти вvoid CMSCollector::acquire_control_and_collect(...)вызывается в этом методе.

Давайте снова посмотрим на first_state:CollectorState first_state = _collectorState;

Глядя на перечисление уже очень понятно, то есть когда cms gc не закончился.

а такжеacquire_control_and_collectЭтот метод предназначен для cms для выполнения переднего плана gc.

CMS делится на Foreground GC и Background GC.

передний план на самом деле полный gc.

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

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

Также возможно, что пороговое значение кучи, установленное cms gc, слишком велико.

Почему полный сборщик мусора является однопоточным, если в CMS GC происходит сбой параллельного режима?

Следующий ответ исходит от R.

Потому что не хватает ресурсов для разработки, я ленив. Это так просто. Технических проблем нет. Крупные компании сделали собственную внутреннюю оптимизацию.

Так как же вы вообще украли этого ленивца? Проблемная CMS GC пережила множество потрясений. Первоначально он был разработан и реализован как GC с малой задержкой для Sun Labs Exact VM.

Однако Exact VM проиграл внутреннюю битву с HotSpot VM за подлинную JVM от Sun, а CMS GC позже была перенесена на HotSpot VM как техническое наследие Exact VM.

В то время как этот перенос еще продолжался, Sun начала проявлять признаки усталости; к тому времени, когда CMS GC был полностью перенесен на HotSpot VM, Sun уже была на грани смерти.

В связи с сокращением ресурсов разработки и потерей разработчиков команда разработчиков HotSpot VM в то время мало что могла сделать, а могла только выбирать важные дела. В это время была запущена другая реализация GC от Sun Labs, Garbage-First GC (G1 GC).

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

Так что на тот момент ресурсов на разработку было не так много, и часть их вкладывалась в проект по коммерциализации G1 GC — результат был медленным прогрессом.

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

Но должны быть некоторые студенты, у которых есть вопросы: Разве в HotSpot VM уже нет параллельного GC? И сколько еще?

Давайте посмотрим:

  • ParNew: Параллельный GC молодого поколения, не отвечающий за сбор старого поколения.
  • Parallel GC (ParallelScavenge): Параллельный сборщик мусора молодого поколения, похожий на ParNew, но не совместимый с ним; также не отвечает за сбор файлов старого поколения.
  • ParalleLold GC (PSCompact): параллельный полный GC, но CMS не совместим с Parnew /.

Итак... все.

В HotSpot VM уже есть параллельный GC, но они оба отвечают только за сбор молодого поколения во время молодого GC.Из них только ParNew можно использовать с CMS;

У параллельного полного GC есть ParallelOld, но он несовместим с CMS GC и не может использоваться в качестве его резервного полного GC.

Почему некоторые старые и новые коллекторы нельзя использовать в комбинации, как ParNew и Parallel Old?

Эту картинку нарисовал член команды GC в HostSpot в 2008 году. На тот момент G1 еще не вышла и находилась в разработке, поэтому на ней был нарисован вопросительный знак.

Ответ внутри:

"ParNew" is written in a style... "Parallel Old" is not written in the "ParNew" style

Собственная реализация сборщика поколений HotSpot VM имеет структуру, и только реализации в рамках этой структуры могут использоваться в сочетании друг с другом.

И один разработчик не захотел реализовывать его по этому фреймворку, поэтому написал его сам, и результаты тестов были неплохие, и он был поглощен HotSpot VM, что привело к несовместимости.

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

Как GC молодого поколения избегает полного сканирования кучи?

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

Приведенное выше изображение имеет точность объекта, одна - точность карты, а точность карты называется карточной таблицей.

Разделите кучу на множество блоков, каждый блок 512 байт (страница карты), используйте элемент в массиве байтов для представления блока, 1 представляет грязный блок, и в нем есть ссылки между поколениями.

Реализация в Hotspot представляет собой карточную таблицу, которая поддерживается пост-записывающим барьером.Псевдокод выглядит следующим образом.

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

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

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

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

В чем разница между набором памяти cms и набором памяти G1?

Реализацией набора памяти CMS является карточный стол или карточный стол.

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

В cms только старое поколение указывает на карточную таблицу молодого поколения, которая используется для gc молодого поколения.

И G1 основан на регионе, поэтому в карточную таблицу точек добавляется структура точек входа.

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

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

Давайте посмотрим на эту картинку, чтобы было понятнее.

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

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

Почему G1 не поддерживает наборы памяти от молодого поколения к старому?

G1 делится на молодую ГК и смешанную ГК.

Young gc выберет для сбора все регионы молодого поколения.

midex gc выберет для сбора все регионы молодого поколения и некоторые регионы старого поколения с высокой доходностью сбора.

такРегионы молодого поколения все входят в состав коллекции, поэтому нет необходимости дополнительно фиксировать межпоколенные ссылки от молодого поколения к старому поколению..

Какие средства использовали cms и G1 для обеспечения корректности параллелизма?

В предыдущей статье были проанализированы два необходимых и достаточных условия для одновременного выполнения недостающих целей:

  1. Вставить новый объект в сканируемый объект, т.е. вставить ссылку на черный объект на белый объект.

  2. Убраны ссылки серых объектов на белые объекты.

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

cms использует добавочное обновление (Incremental update), чтобы нарушить первое условие, пометить вставленный белый объект как серый через барьер записи, то есть добавить его в стек меток, и снова сканировать в фазе примечания, чтобы предотвратить пропущенные метки.

G1 использует SATB (моментальный снимок в начале), чтобы нарушить второе условие: он запишет старую эталонную взаимосвязь через барьер записи, а затем снова просканирует старую эталонную взаимосвязь.

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

И вновь выделенные объекты в процессе сборки мусора также считаются живыми. Каждая область поддерживает указатель TAMS (верхнее начало метки), который является положением указателя Top, когда prevTAMS и nextTAMS отмечают начало двух параллельных меток соответственно.

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

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

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

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

Что такое барьер записи журнала?

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

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

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

Подобно барьеру записи SATB, каждый поток Java имеет независимую SATBMarkQueue фиксированной длины, и в очередь барьера записи помещаются только старые ссылки. Когда он заполнится, он будет добавлен в глобальный набор SATBMarkQueueSet.

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

Барьер записи журнала также используется для поддержания барьера записи набора памяти.

Кратко объясните процесс переработки G1

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

одновременная маркировкаОн основан на STAB и может быть разделен на четыре этапа:

1. Начальная маркировка, этот этап - STW, сканирование корневого набора и отметка объектов, непосредственно доступных для корня. Маркировка объектов в G1 записывается с использованием внешнего растрового изображения, а не заголовка объекта.

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

3. Окончательная маркировка (окончательная маркировка), этот этап является STW и обрабатывает ссылки в STAB.

4.Фаза зачистки(cleanaup),эта фаза STW.По отмеченному битмапу подсчитывается количество уцелевших объектов в каждом регионе.Если есть регион,который не уцелел вообще,он будет переработан целиком .

Этап копирования объекта(эвакуация), этот этап - STW.

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

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

Коротко о процессе утилизации cms

На самом деле несколько процессов можно узнать из перечисления CollectorState из предыдущего вопроса.

1,начальная отметка, этот этап — STW, сканирование корневой коллекции и пометка объектов, непосредственно доступных для корня.

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

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

4.Прерываемая фаза предварительной очистки (AbortablePreclean), который в основном аналогичен предыдущему этапу, просто чтобы разделить работу по перемаркировке.

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

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

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

Узким местом CMS является фаза повторной маркировки, которая требует много времени для повторного сканирования.

Барьер записи cms также является таблицей карт обслуживания, и он должен поддерживать добавочные обновления?

На самом деле карточная таблица всего одна, и ее точно недостаточно для поддержки YGC и инкрементных обновлений при параллельной работе CMS.

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

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

Таким образом, этап перемаркировки cms может комбинировать текущую таблицу карт и таблицу модов-объединений для обработки добавочных обновлений для предотвращения потери объектов.

Каковы две цели настройки GC?

соответственноМинимальное время паузы и пропускная способность.

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

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

Например:

Вариант 1: Каждый GC делает паузу на 100 мс, 5 пауз в секунду.

Вариант 2: каждый GC делает паузу на 200 мс, 2 паузы в секунду.

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

Поэтому при настройке необходимо уточнить цели приложения..

Как настраивается GC

Этот вопрос легко задать на собеседовании, поэтому хватайтесь за основу и отвечайте на него.

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

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

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

Затем отрегулируйте в соответствии с реальной ситуацией.

Например, если выполняется необъяснимая полная сборка мусора, возможно, сторонняя библиотека с именем System.gc.

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

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

наконец

На самом деле анализа содержания ZGC до сих пор нет, не волнуйтесь, статья по ZGC написана наполовину и будет опубликована позже.

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

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

Конечно, если вы хотите узнать больше деталей GC, просто посмотрите исходный код, в исходном коде нет никаких секретов.

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

плечи гигантов

сегмент fault.com/ah/119000002…

Blogs.orcle.com/jon Tianhe City Ol есть ...

Woohoo.ITeye.com/blog/user/th…Блог Big R

woohoo.brief.com/U/90AB66С 24…аккаунт в блоге волка


Я да, от немного до миллиарда немного, увидимся в следующей статье.