Модель памяти Java

интервью Java JVM

Когда в интервью спрашивают о «модели памяти», обычно речь идет о расследовании.Структура памяти Java и GC,Вместо более глубокого и подробного контента, такого как Happens-Before. Модель памяти предназначена для проверки способности программиста понимать язык, что в дальнейшем распространяется на глубину оптимизации JVM и обучение в мирное время.Это самая важная часть собеседования по Java. Здесь отсортированы точки знаний о структуре памяти и GC. Ожидается, что модель Happens-Before будет отсортирована после изучения JVM в будущем.

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

структура памяти

Введение в структуру памяти

Структура памяти JVM примерно делится на:

  1. Куча: разделяется потоками, все экземпляры объектов и массивы должны размещаться в куче. Объект, которым в основном управляет сборщик.
  2. ОБЛАСТЬ МЕТОДОВ: совместное использование потоков, хранение информации о классе, констант, статических переменных и кода, скомпилированного компилятором реального времени.
  3. Стек методов (стек JVM): частный поток, таблица локальных переменных хранилища, стек операций, динамическая ссылка, выход из метода, указатель объекта.
  4. НАТИВНЫЙ СТЕК МЕТОДОВ: Частный поток. Обслуживает собственные методы, используемые виртуальными машинами. Например, когда Java использует сервисы интерфейса, написанные на C или C++, код выполняется в этой области.
  5. Регистрация ПК: Частный поток. Указывает на следующую команду для выполнения.

image.png
image.png

Подробное описание каждой области

В структуре памяти Java мы фокусируемся на области кучи и методов.

image.png
image.png

куча

Роль кучи заключается в хранении экземпляров объектов и массивов. С точки зрения структуры его можно разделить на новое поколение и старое поколение. Новое поколение можно разделить на пространство Эдема, пространство От выжившего (s0), пространство до выжившего (s1). Все вновь сгенерированные объекты сначала помещаются в молодое поколение. Следует отметить, что две области Выжившего симметричны, и между ними нет никакой связи, поэтому в одной и той же области в одно и то же время могут находиться объекты, скопированные из Эдема, и объекты, скопированные из предыдущего Выжившего, а копия в старая область есть только у первого выжившего, пришедшего на объект. Кроме того, одна из областей Выживших всегда пуста.

параметр управления

-Xms устанавливает минимальный размер кучи. -Xmx устанавливает максимальный размер кучи. -XX:NewSize устанавливает минимальный размер пространства для нового поколения. -XX:MaxNewSize устанавливает минимальный размер пространства для нового поколения.

вывоз мусора

Эта область является основной рабочей зоной для сбора мусора.

ненормальная ситуация

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

область метода

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

Многие люди готовы называть область методов «постоянной генерацией». По сути, они не эквивалентны только потому, что команда разработчиков виртуальной машины HotSpot решила расширить коллекцию поколений GC до области методов или использовать постоянную генерацию. Генерация для реализации только области метода. Для других виртуальных машин (таких как BEA JRockit, IBM J9 и т. д.) понятие постоянной генерации отсутствует. В Java 8 бессмертное поколение полностью исчезло.

параметр управления

-XX:PermSize Установить минимальное пространство -XX:MaxPermSize Установить максимальное пространство.

вывоз мусора

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

ненормальная ситуация

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

стек методов

Каждый поток будет иметь частный стек. Вызов метода в каждом потоке создает кадр стека в этом стеке. В стеке методов будут храниться различные базовые типы данных (boolean, byte, char, short, int, float, long, double) и ссылки на объекты (ссылочные типы, которые не эквивалентны самому объекту), известные во время компиляции. Требуемый объем памяти выделяется во время компиляции, при входе в метод полностью определяется, сколько места для локальной переменной этот метод должен выделить во фрейме, и размер таблицы локальных переменных не будет изменен во время выполнения метода.

параметр управления

-Xss управляет размером стека каждого потока.

ненормальная ситуация

В Спецификации виртуальной машины Java для этой области указаны два исключительных условия:

  1. StackOverflowError: вызывается, когда глубина стека, запрошенная потоком исключений, превышает глубину, разрешенную виртуальной машиной;
  2. Исключение OutOfMemoryError: стек виртуальной машины может быть динамически расширен, и он будет сгенерирован, когда во время расширения не может быть выделено достаточно памяти.

собственный стек методов

Роль собственного стека методов (Native Method Stacks) и стека виртуальной машины очень похожа.
Разница только в том, что стек виртуальной машины обслуживает выполнение виртуальной машиной методов Java (то есть байт-кода), в то время как собственный стек методов
Это собственная служба методов, используемая виртуальной машиной.

параметр управления

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

ненормальная ситуация

Как и стек виртуальной машины, область стека собственных методов также выдает StackOverflowError и OutOfMemoryError.
аномальный.

Счетчик ПК

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

ненормальная ситуация

Эта область памяти является единственной областью, в которой не указаны какие-либо условия OutOfMemoryError в спецификации виртуальной машины Java.

Ссылаться на:
Подробное объяснение виртуальной машины Java 02 ---- структура памяти JVM
Структура памяти JVM

GC

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

Просмотрите модель кучи памяти

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

Память кучи освобождается автоматической системой управления памятью сборщика мусора.
Память кучи делится на две части: молодое поколение и старое поколение. Соотношение 1:2.
Старое поколение в основном хранит в приложении уцелевшие объекты с длительным жизненным циклом.
Новое поколение разделено на три части: одна область Эдема и две области Выживших, с соотношением 8:1:1.
Район Эдема хранит новые объекты.
Survivor хранит объекты, пережившие каждую сборку мусора.

image.png
image.png

Обратите внимание на эти вопросы:

  1. Зачем разделять новое поколение и старое поколение?
  2. Почему Кайнозой разделен на одну область Эдема и две области Выживших?
  3. Почему соотношение одной области Эдема и двух областей Выживших 8:1:1?

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

Определить перерабатываемые объекты

Прежде чем заняться сборкой мусора, нам нужно прояснить вопрос — какие объекты являются мусором (бесполезными объектами) и их нужно собирать?

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

алгоритм подсчета ссылок

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

image.png
image.png

Преимущество в том, что он прост и эффективен, и текущая цель-с использует этот алгоритм.

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

Этот недостаток является фатальным.Некоторые люди могут спросить, а не правильно ли используется Objective-C? Я лично не думаю, что Objective-C хорошо справляется с этой проблемой циклических ссылок, он на самом деле перекладывает эту проблему на разработчиков.

Алгоритм анализа достижимости (алгоритм поиска корня)

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

Начиная с GC Roots (каждая конкретная реализация имеет разные определения для GC Roots), поиск объектов, на которые они ссылаются, может создать ссылочное дерево.Узлы дерева рассматриваются как достижимые объекты, и наоборот.

image.png
image.png

Хорошо, даже если есть циклическая ссылка, пока на нее не ссылается GC Roots, она все равно будет переработана, отлично!

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

  1. Объекты, на которые есть ссылки в стеке виртуальной машины (таблица локальных переменных в стеке фреймов).
  2. Объект, на который ссылается статическое свойство в области метода.
  3. Объект, на который ссылается константа в области метода.
  4. Объекты, на которые ссылается JNI в собственном стеке методов.

Stop The World

Вместе с приведенным выше суждением о мусорных объектах мы должны рассмотреть еще один вопрос, пожалуйста, приготовьтесь, а именно: «Остановите мир».

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

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

Отсюда и проблема лага GC, что тоже простительно и неизбежно пока.

вывоз мусора

Я уже знаю, что такое мусорные объекты, как их перерабатывать?

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

Марк-развертка

Алгоритм маркировки-развертки делится на две фазы: фазу маркировки и фазу развертки. Задача этапа маркировки — пометить все объекты, которые необходимо вернуть, а этапа очистки — вернуть место, занимаемое отмеченными объектами.

image.png
image.png

Достоинства: Простая реализация.

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

Алгоритм копирования (копирование)

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

image.png
image.png

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

Недостаток: Использование памяти дорого, потому что память, которую можно использовать, уменьшается вдвое.

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

Марк-компактный алгоритм

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

image.png
image.png

Преимущества: простая реализация, непростое создание фрагментации памяти и эффективное использование памяти.

Недостаток: очень неэффективно.

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

Алгоритм повторного использования поколений

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

Вот применимые сценарии двух старых алгоритмов:

Алгоритм копирования: применяется к нескольким уцелевшим объектам. Много объектов переработки
Алгоритм маркировки и сортировки: подходит для большего количества уцелевших объектов и меньшего количества объектов, подлежащих переработке

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

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

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

Конкретно:

  1. Для нового поколения, хотя алгоритм репликации принят, на практике пространство нового поколения не делится в соответствии с соотношением 1:1, упомянутым в вышеприведенном алгоритме, а новое поколение делится на большее пространство Эдема и два блока меньшего размера для выживших с соотношением 8:1:1. Зачем? Подробный анализ в следующем разделе.
  2. Старость характеризуется тем, что при каждой коллекции собирается лишь небольшое количество объектов, что согласуется с основной характеристикой устойчивой системы - более половины объектов будут находиться в памяти длительное время. Следовательно, соотношение старого поколения больше, чем у молодого поколения, а соотношение нового поколения к старому по умолчанию составляет 1:2.

Это алгоритм сбора поколений.

Глубокое понимание алгоритма рециркуляции поколений

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

Почему не одно место для выживших, а два?

Это включает в себя жизненный цикл нового поколения и старого поколения. Например, объект может быть перемещен в старое поколение после 15 GC в новом поколении (только для справки). Здесь возникает проблема, когда мы делаем первый GC, мы можем поместить уцелевшие объекты в области Эдема в пространство Survivor A, но во втором GC уцелевшие объекты в пространстве Survivor A также должны снова использовать алгоритм копирования. и поместите их на ячейку Выжившего А. На ячейке Выжившего Б только что очистите ячейку Выжившего А и ячейку Эдема. Во время третьего GC уцелевшие объекты в пространстве Survivor B копируются в пространство Survivor A и так далее.

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

Почему пространство Эдема такое большое, а пространство Выживших менее разделено?

Вновь созданные объекты помещаются в пространство Эдема, что бывает очень часто, особенно временные объекты, генерируемые большим количеством локальных переменных.Большинство этих объектов следует немедленно перерабатывать, а те, что могут уцелеть, перенести в пространство оставшихся в живых часто не много. Поэтому разумно установить большее пространство Eden и меньшее пространство Survivor, что значительно улучшает использование памяти и устраняет недостатки алгоритма копирования.

Я думаю, что 8: 1: 1 это хорошо.Конечно, это соотношение можно регулировать, в том числе соотношение 1: 2 нового поколения и старого поколения выше.

Снова возникает новая проблема: что делать, если места Выжившего не хватает при переходе из пространства Эдема в пространство Выжившего? Идите прямо к старости.

Рабочий процесс пространства Eden и двух пространств Survivor

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

Теперь предположим, что есть три пространства нового поколения Eden, Survivor A и Survivor B и одно пространство старого поколения Old.

// 分配了一个又一个对象
放到Eden区
// 不好,Eden区满了,只能GC(新生代GC:Minor GC)了
把Eden区的存活对象copy到Survivor A区,然后清空Eden区(本来Survivor B区也需要清空的,不过本来就是空的)
// 又分配了一个又一个对象
放到Eden区
// 不好,Eden区又满了,只能GC(新生代GC:Minor GC)了
把Eden区和Survivor A区的存活对象copy到Survivor B区,然后清空Eden区和Survivor A区
// 又分配了一个又一个对象
放到Eden区
// 不好,Eden区又满了,只能GC(新生代GC:Minor GC)了
把Eden区和Survivor B区的存活对象copy到Survivor A区,然后清空Eden区和Survivor B区
// ...
// 有的对象来回在Survivor A区或者B区呆了比如15次,就被分配到老年代Old区
// 有的对象太大,超过了Eden区,直接被分配在Old区
// 有的存活对象,放不下Survivor区,也被分配到Old区
// ...
// 在某次Minor GC的过程中突然发现:
// 不好,老年代Old区也满了,这是一次大GC(老年代GC:Major GC)
Old区慢慢的整理一番,空间又够了
// 继续Minor GC
// ...
// ...

Тип срабатывания ГХ

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

  • GC_FOR_MALLOC: указывает, что сборщик мусора запускается из-за нехватки памяти при размещении объектов в куче.
  • GC_CONCURRENT: Когда куча памяти нашего приложения достигает определенного объема или можно понять, что она вот-вот будет заполнена, система автоматически запустит операцию GC для освобождения памяти.
  • GC_EXPLICIT: указывает, что сборщик мусора запускается, когда приложение вызывает интерфейс System.gc, VMRuntime.gc или получает сигнал SIGUSR1.
  • GC_BEFORE_OOM: указывает, что сборщик мусора был запущен как последняя попытка перед подготовкой к созданию исключения OOM.

Ссылаться на:


Ссылка на эту статью:Модель памяти Java
автор:обезьяна 007
Источник:monkeysayhi.github.io
Эта статья основана наCreative Commons Attribution-ShareAlike 4.0Международное лицензионное соглашение выпущено, его можно перепечатать, вывести или использовать в коммерческих целях, но авторство и ссылка на эту статью должны быть сохранены.