Недавно я читал книгу "JAVA Concurrent Programming Practice", в которой рассказывалось о модели памяти Java. Структура памяти JVM естественным образом пришла через модель памяти Java. Познание структуры памяти JVM до сих пор изучается на занятиях в университете. Я не изучал эти знания систематически, поэтому на этот раз я поставил «Углубленное понимание расширенных функций и лучших практик JVM виртуальной машины Java», «Спецификация виртуальной машины Java Java SE 8 Edition». Две книги о структуре памяти JVM, которые у меня есть прочитайте все его части, и считается, что он имеет новое понимание структуры памяти JVM. Структура памяти JVM относится к: виртуальная машина Java определяет несколько областей данных времени выполнения, которые будут использоваться во время выполнения программы, некоторые из которых будут созданы при запуске виртуальной машины, уничтожены при выходе из виртуальной машины, а некоторые связаны с потоками. Индивидуальная корреспонденция, созданная при запуске потока и уничтоженная при завершении потока. Конкретная область данных времени выполнения показана на следующем рисунке:
В Спецификации виртуальной машины Java определены пять областей данных времени выполнения, а именно куча Java, область методов, стек виртуальной машины, локальная область методов и счетчик программ.Куча Java и область методов совместно используются потоками. Далее давайте подробно рассмотрим эти пять областей данных времени выполнения.
Куча Java (куча)
Куча Java — это область памяти, совместно используемая всеми потоками, которая создается при запуске виртуальной машины, и у одного процесса JVM есть одна и только одна куча Java. Куча Java используется для хранения экземпляров объектов и массивов, а это означает, что здесь хранятся новые объекты в нашем коде через новое ключевое слово. Поэтому он стал основным лагерем деятельности сборщика мусора, поэтому у него есть псевдоним, называемый кучей GC.Согласно правилам сборщика мусора, мы можем дополнительно разделить кучу Java.Конкретная структура памяти кучи Java показана ниже :
Мы можем разделить кучу Java на два больших модуля: новое поколение и старое поколение, В новом поколении мы можем дополнительно разделить его на пространство Эдема, пространство из оставшегося в живых (s0), пространство в оставшееся в живых (s1) и оставшееся в живых пространство имеет место для пустого, используемого для хранения выживших объектов, когда происходит GC.Старость хранит объекты, которые выживают после нескольких незначительных GC или некоторых больших объектов.FGC происходит в старости.
Выше приведена конкретная структура кучи Java. Мы также знаем размер каждого пространства в куче Java, которым мы можем динамически управлять. Я также кратко отметил это на рисунке. Давайте подробно рассмотрим эти три параметра:
- -Xms: начальное значение кучи, применяемое при запуске JVM, по умолчанию равно 1/64 физической памяти операционной системы, например -Xms20m.
- -Xmx: максимальное значение кучи, к которому может обращаться JVM. Значение по умолчанию — 1/4 физической памяти. Например, -Xmx20m, лучше установить для -Xms и -Xmx одно и то же значение, чтобы избежать повторного использования JVM. выделение памяти после завершения каждой сборки мусора;
- -Xmn: установить размер памяти нового поколения, -Xmn установить NewSize и MaxNewSize одинаковыми, мы также можем установить эти два параметра отдельно
Исключения OOM будут возникать в куче Java.Когда в нашей куче Java будет достаточно места для завершения выделения экземпляра, а куча не может быть расширена, будет выдано наше обычное исключение OutOfMemoryError, как показано на следующем рисунке:
По поводу исключения OOM хочу еще сказать вот что.В интернете есть очень популярный вопрос на собеседовании:JVM 堆内存溢出后,其他线程是否可继续工作?
, я лично считаю, что многие ответы неверны, и кому интересно, могут изучить.
Область метода
Область методов, как и куча Java, представляет собой область памяти, совместно используемую каждым потоком, и является единственной общей областью памяти в виртуальной машине Java. Область метода определена в Спецификации виртуальной машины Java следующим образом: она хранит структурную информацию каждого класса, такую как пул констант времени выполнения, поля, данные метода, содержимое байт-кода конструкторов и обычных методов, а также включает некоторые в класс. , например, специальный метод, используемый при инициализации интерфейса.
Область методов создается при запуске виртуальной машины.Хотя область методов является логической частью кучи, простая реализация виртуальной машины может не реализовывать сбор мусора и сжатие в этой области, а область методов может не быть непрерывной в фактическое пространство памяти. , для емкости области метода вы можете зафиксировать, или вы можете динамически расширяться при выполнении программы и автоматически уменьшаться, когда слишком много места не требуется.
Выше приведены все спецификации виртуальной машины Java. Давайте взглянем на конкретную реализацию. Возьмем в качестве примера нашу часто используемую виртуальную машину HotSpot. До JDK1.8 область методов также называлась постоянным поколением. Эта область методов будет случиться с нашим общимjava.lang.OutOfMemoryError: PermGen space
Исключение, мы также можем контролировать размер области метода через параметры запуска:
- -XX:PermSizeустановить минимальное пространство
- -XX:MaxPermSizeустановить максимальное пространство
После JDK1.8 виртуальная машина HotSpot внесла множество изменений в область методов, полностью удалила постоянное поколение, перенесла данные, изначально хранившиеся в постоянном поколении, в кучу Java или метапространство, область методов была перемещена в метапространство, константы символов String перемещены в Java Heap, другими словами, начиная с JDK1.8, метапространство — это то, что мы называем областью методов.Почему вы хотите внести это изменение? Возможно, по следующим двум причинам:
- Поскольку память PermGen часто переполняется, вызывая раздражающую ошибку java.lang.OutOfMemoryError: PermGen, разработчики JVM надеются, что этим участком памяти можно будет управлять более гибко, и такой OOM не будет возникать часто
- Удаление PermGen может облегчить интеграцию HotSpot JVM с JRockit VM, поскольку JRockit не имеет постоянного поколения.
Мы также можем контролировать размер пространства Metaspace, устанавливая параметры, в основном это следующие команды:
- -XX:MetaspaceSize: начальный размер (в байтах), выделенный для пространства метаданных класса. Установка слишком большого значения MetaspaceSize продлит время сборки мусора. После сборки мусора размер пространства метаданных класса, вызывающего следующую сборку мусора, может увеличиться.
- -XX:MaxMetaspaceSize: максимальное значение, выделенное для пространства метаданных класса. Если это значение превышено, будет запущена полная сборка мусора. Это значение не имеет ограничений по умолчанию, но оно должно зависеть от размера системной памяти. JVM динамически изменяет это значение.
- -XX:MinMetaspaceFreeRatio: указывает, что после GC, чтобы избежать увеличения размера пространства метаданных, минимальная доля емкости метаданных свободного класса, если этого недостаточно, приведет к сборке мусора.
- -XX:MaxMetaspaceFreeRatio: Указывает, что после GC, во избежание увеличения размера пространства метаданных, максимальная доля емкости метаданных свободного класса, если этого недостаточно, приведет к сборке мусора.
Стеки виртуальных машин Java (стеки JVM)
Каждый поток виртуальной машины Java имеет свой собственный стек виртуальной машины Java. Этот стек виртуальной машины Java создается одновременно с потоком, поэтому он имеет тот же жизненный цикл, что и поток.Стек виртуальной машины Java описывает модель памяти выполнения метода Java: каждый метод при выполнении создает кадр стека, который используется для хранения такой информации, как таблица локальных переменных, стек операндов, динамическая ссылка, выход из метода и т. д. Процесс вызова до завершения выполнения соответствует процессу помещения кадра стека в стек в стеке виртуальной машины Java.
В таблице локальных переменных хранятся различные основные типы данных, известные во время компиляции (boolean, byte, char, short, int, float, long, double), ссылки на объекты (тип ссылки, который не эквивалентен самому объекту, согласно различным виртуальным машины, это может быть ссылочный указатель на начальный адрес объекта или он может указывать на дескриптор, представляющий объект или другое местоположение, связанное с объектом) и тип returnAddress (указывающий на адрес инструкции байт-кода).
64-битные типы данных long и double занимают 2 пространства локальных переменных (слотов), а остальные типы данных занимают только 1. Объем памяти, требуемый таблицей локальных переменных, выделяется во время компиляции.При входе в метод полностью определяется, сколько места локальной переменной этот метод должен выделить во фрейме, и размер таблицы локальных переменных не будет изменяться во время выполнения. выполнение метода.
Стек виртуальной машины Java может быть реализован с фиксированным размером, а также может динамически расширяться и сокращаться в соответствии с расчетами.Если используется фиксированный размер, емкость стека виртуальной машины Java для каждого потока может быть выбрана независимо, когда поток созданный. В стеке виртуальной машины Java возникают два исключения, указанные в спецификации виртуальной машины:
- Если размер стека, запрошенный потоком, превышает максимальный размер, разрешенный стеком виртуальной машины Java, виртуальная машина Java выдаст исключение StackOverflowError;
- Если стек виртуальной машины Java может быть динамически расширен и не может запросить достаточно памяти при попытке расширения, или если памяти недостаточно для создания соответствующего стека виртуальной машины Java при создании нового потока, виртуальная машина выдаст ошибку OutOfMemoryError. исключение .
Регистр счетчика программ
Счетчик программ также является потоко-приватным, ему требуется только небольшой объем памяти, вы можете думать о нем как о индикаторе номера строки байт-кода, выполняемого текущим потоком, в концептуальной модели виртуальной машины (только концептуальная модель, Различные виртуальные машины могут быть реализованы более эффективными способами), когда интерпретатор байт-кода работает, он выбирает следующую инструкцию байт-кода для выполнения, изменяя значение этого счетчика, перехода, цикла, перехода, исключения. Основные функции, такие как обработка и поток восстановление необходимо полагаться на этот счетчик для завершения.
Мы знаем, что в случае многопоточности за все время выполняется не один поток, а несколько потоков переключают выполнение по очереди, поэтому для того, чтобы восстановить правильную позицию выполнения после переключения потоков, нам нужен программный счетчик, сообщающий thread что делать дальше Какую инструкцию выполнять. Если поток выполняет метод Java, этот счетчик записывает адрес выполняемой инструкции байт-кода виртуальной машины.Если поток выполняет метод Natvie, значение счетчика пусто (не определено).
Важно отметить, чтоСчетчик программ — единственная область, в которой в спецификации виртуальной машины Java не указаны условия OutOfMemoryError..
Стеки нативных методов
Стеки собственных методов (Native Method Stacks) и стек виртуальной машины Java играют очень похожую роль, разница в том, что стек виртуальной машины Java служит виртуальной машине для выполнения методов Java (то есть байт-кода), в то время как собственный стек методов Это собственная служба методов, используемая виртуальной машиной. Спецификация виртуальной машины не определяет язык, использование и структуру данных методов в собственном стеке методов, поэтому конкретная виртуальная машина может свободно реализовать ее. Даже некоторые виртуальные машины (например, виртуальная машина Sun HotSpot) напрямую объединяют собственный стек методов и стек виртуальной машины в один.
Как и стек виртуальной машины Java, область стека собственных методов также выдает исключения StackOverflowError и OutOfMemoryError.
Ссылаться на
- «Глубокое понимание расширенных функций и лучших практик JVM виртуальной машины Java»
- "Спецификация виртуальной машины Java Java SE 8 Edition"
В конце концов
В настоящее время многие большие ребята в Интернете имеют статьи, связанные со структурой памяти JVM, Если есть какие-то сходства, пожалуйста, потерпите меня. Нелегко быть оригинальным, и нелегко кодировать слова, я также надеюсь, что вы поддержите это. Если в тексте есть какие-либо ошибки, я хотел бы указать на них. Спасибо. Добро пожаловать, чтобы отсканировать код и подписаться на общедоступную учетную запись WeChat: «Технический блог брата Пинтоу». Брат Пинтоу будет учиться и делать успехи вместе.