Область данных среды выполнения Java

JVM

область данных времени выполнения

image-20211217162311784

image-20211217162549042

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

счетчик команд

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

Счетчик программ выполняет две основные функции:

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

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

Стек виртуальной машины Java

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

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

В стеке виртуальной машины Java есть два типа ошибок:StackOverFlowErrorа такжеOutOfMemoryError.

  • StackOverFlowError:Если объем памяти стека виртуальной машины Java не позволяет динамическое расширение, когда глубина стека запросов потока превышает максимальную глубину текущего стека виртуальной машины Java, будет выдана ошибка StackOverFlowError.
  • OutOfMemoryError:Размер памяти стека виртуальной машины Java может быть динамически расширен.Если виртуальная машина не может запросить достаточно места в памяти при динамическом расширении стека, она будет выброшена.OutOfMemoryErrorаномальный.

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

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

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

В сочетании со стеком виртуальной машины Java в виртуальной машине HotSpot.

куча

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

"Почти" все объекты в мире Java размещаются в куче. Однако с развитием JIT-компиляторов и постепенным развитием методов escape-анализа методы оптимизации выделения стека и скалярной замены приведут к некоторым тонким изменениям. куча постепенно становится менее «абсолютной». Начиная с JDK 1.7 escape-анализ включен по умолчанию.Если ссылка на объект в каких-то методах не возвращается или не используется снаружи (то есть не экранируется), то объект может напрямую выделять память в стеке.

Куча Java — это основная область, управляемая сборщиком мусора, поэтому она также называетсяКуча мусора. С точки зрения сборки мусора, поскольку сборщик в основном принимает алгоритм сборки мусора поколений, куча Java также может быть подразделена на: новое поколение и старое поколение; немного более подробно: пространство Эдема, от выжившего, до оставшегося в живых, и т.п.Целью дальнейшего деления является более эффективное использование памяти или ее более быстрое выделение.

С точки зрения восстановления памяти, поскольку большинство современных сборщиков мусора разработаны на основе теории сборки поколений, в Java часто встречаются «новое поколение», «старое поколение», «постоянное поколение», «пространство Эдема» и «от выжившего». heap.Space", "To Survivor space" и другие термины, эти деления областей являются лишь общими характеристиками или стилями дизайна некоторых сборщиков мусора, а не внутренней структурой памяти конкретной реализации виртуальной машины Java или "Java Virtual Спецификация машины». Здесь представлено более подробное разделение кучи Java. Во многих материалах часто говорится что-то вроде "Куча памяти виртуальной машины Java делится на новое поколение, старое поколение, постоянное поколение, Эдем, Выживший...". Десять лет назад (с появлением сборщика G1 в качестве границы), когда виртуальная машина HotSpot была абсолютной основной в отрасли, все ее внутренние сборщики мусора были разработаны на основе «классического поколения» [3], требующего нового поколения, старого поколения. Сборщики могут работать только с коллокацией, но сейчас это не то, и есть сборщики мусора, которые не используют генерационный дизайн.

В версиях JDK 7 и до версии JDK 7 память кучи обычно делилась на следующие три части:

  1. Молодое поколение
  2. Старое поколение
  3. Постоянное поколение

image-20211217165250972

После версии JDK 8 область методов (постоянная генерация HotSpot) была полностью удалена (JDK1.7 уже запущена) и заменена метапространством, которое использует прямую память.

image-20211217165410792

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

В большинстве случаев объект сначала будет размещен в области Эдема.После сборки мусора нового поколения, если объект еще жив, он войдет в s0 или s1, а возраст объекта также увеличится на 1 (область Эдема). -> Область выжившего после возраста объекта Начальный возраст становится равным 1), и когда его возраст увеличивается до определенного уровня (по умолчанию 15), он будет переведен в старое поколение. Порог возраста для перевода объекта в старое поколение, который можно передать через параметр-XX:MaxTenuringThresholdустанавливать.

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

Скорее всего, в куче появится ошибка OutOfMemoryError, и после возникновения этой ошибки будет несколько проявлений, например:

  1. java.lang.OutOfMemoryError: GC Overhead Limit Exceeded: Эта ошибка возникает, когда JVM тратит слишком много времени на сборку мусора и может освободить только небольшое пространство кучи.
  2. java.lang.OutOfMemoryError: Java heap space: эта ошибка возникает, если в памяти кучи недостаточно места для хранения вновь созданного объекта при создании нового объекта. (Это связано с настроенной максимальной памятью кучи и ограничено размером физической памяти. Максимальную память кучи можно передать через-Xmxконфигурация параметров,-XmsУстановите начальную память кучи. Если нет специальной конфигурации, будет использоваться значение по умолчанию. Подробнее см.:Default Java 8 max heap size (opens new window))

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

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

Когда дело доходит до области методов, я должен упомянуть концепцию «постоянной генерации», особенно до JDK 8, многие программисты Java привыкли разрабатывать и развертывать программы на виртуальной машине HotSpot, и многие люди предпочитают называть область методов «Перманентное поколение» (Permanent Generation) или их комбинация. По сути, они не эквивалентны, потому что только группа разработчиков виртуальных машин HotSpot в то время решила расширить дизайн коллектора на уровне методов илиИспользуйте постоянное поколение для реализации области методаВот и все, так что сборщик мусора HotSpot может управлять этой частью памяти, такой как куча Java, избавляя от работы по написанию кода управления памятью специально для области методов. Но для других реализаций виртуальных машин, таких как BEA JRockit, IBM J9 и т. д., не существует концепции постоянной генерации. В принципе, способ реализации области метода относится к деталям реализации виртуальной машины, не регулируется «Спецификацией виртуальной машины Java» и не требует унификации. Но сейчас, оглядываясь назад, можно сказать, что решение использовать постоянное поколение для реализации области метода было плохой идеей.Это повышает вероятность того, что Java-приложения будут сталкиваться с проблемами переполнения памяти.(Постоянная генерация имеет верхний предел -XX: MaxPermSize,Размер по умолчанию, даже если он не установлен, в то время как J9 и JRockit не имеют проблем, пока они не достигают верхнего предела доступной памяти процесса, такого как предел 4 ГБ в 32-разрядной системе), и существует очень мало методов (таких как String::intern()), который не будет работать из-за постоянной генерации, поэтому разные виртуальные машины имеют разную производительность. Когда Oracle приобрела BEA и стала владельцем JRockit, она собиралась перенести превосходные функции JRockit, такие как инструменты управления Java Mission Control, на виртуальную машину HotSpot, но столкнулась со многими трудностями из-за различий в реализации метода. область между двумя.

Принимая во внимание будущее развитие HotSpot, команда разработчиков HotSpot отказалась от постоянного поколения в JDK 6 и постепенно перешла наИспользуйте Native Memory для реализации области методаВ HotSpot JDK 7 пул строковых констант и статические переменные, которые изначально были помещены в постоянную генерацию, были удалены, а в JDK 8 от концепции постоянной генерации, наконец, полностью отказались, и использование JRockit вместо метапространство (Metaspace), реализованное в локальной памяти наподобие J9, перемещает все оставшееся содержимое (в основном информацию о типах) постоянного поколения в JDK 7 в метапространство.

//JDK 1.8 之前永久代还没被彻底移除的时候通常通过下面这些参数来调节方法区大小
-XX:PermSize=N //方法区 (永久代) 初始大小
-XX:MaxPermSize=N //方法区 (永久代) 最大大小,超过这个值将会抛出 OutOfMemoryError 异常:java.lang.OutOfMemoryError: PermGen

В JDK 1.8 область методов (постоянная генерация HotSpot) была полностью удалена (JDK 1.7 уже запущена) и заменена метапространством, которое использует прямую память.

//一些常用参数:
-XX:MetaspaceSize=N //设置 Metaspace 的初始(和最小大小)
-XX:MaxMetaspaceSize=N //设置 Metaspace 的最大大小

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

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

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

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

Точка доступа JDK1.8 удалила метапространство постоянной замены (Metaspace) и заменила его, на этот разПул строковых констант все еще находится в куче, Пул констант среды выполнения все еще находится в области методов., но реализация области метода изменилась с постоянного поколения на Metaspace.

прямая память

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

Новое в JDK1.4Класс NIO (новый ввод/вывод), представляет метод ввода-вывода, основанный на канале (Channel) и буфере (Buffer), который может напрямую использовать библиотеку собственных функций для прямого выделения памяти вне кучи, а затем использовать объект DirectByteBuffer, хранящийся в куче Java, в качестве этой ссылки на память. работать. Это может значительно повысить производительность в некоторых сценариях за счет предотвращения копирования данных туда и обратно между кучей Java и собственной кучей.

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