Серия JVM (2) — область памяти JVM

Java задняя часть JVM Операционная система

предисловие

JVMОбласть памяти включает в себяСчетчик ПК,Стек виртуальной машины Java,собственный стек методов,куча,область метода,постоянный пул времени выполненияипрямая память.

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

текст

(1) Область памяти JVM

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

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

Примечание. Счетчик программ, стек виртуальной машины и собственный стек методов принадлежат каждомуприватный поток; области кучи и методов принадлежатОбщий доступ к потоку.

1.1 Счетчик ПК

счетчик команд (Program Counter Register) это кусокменьшепространство памяти, его роль можно рассматривать какТекущий потоквыполненныйиндикатор номера строки байт-кода.

  1. Байт-код, выполняемый текущим потокоминдикатор номера строки.
  2. У каждой нити свояPCприлавок.
  3. нитьчастный, жизненный цикл такой же, как у потока, сJVMродился, чтобы начать,JVMЗакрой и умри.
  4. выполнение потокаJavaметод, запишите виртуальную машину, на которой он выполняетсяадрес инструкции байт-кода.
  5. выполнение потокаNativeметод, счетчик регистрируется какнулевой(Undefined).
  6. только вJavaСпецификация виртуальной машины не указывает никакихOutOfMemoryErrorрайон ситуации.

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

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

  1. таблица локальных переменных
  2. стек операндов
  3. динамическая ссылка
  4. экспорт метода

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

Объясни в свою очередькадр стекаКонкретная структура и функция четырех составляющих элементов в:

1). Локальная переменная таблица

таблица локальных переменныхэто группаПеременнаяскладских помещений для храненияпараметры методаилокальная переменная. существуетClassЛист метода файловCodeатрибутmax_localsуказывает таблицу локальных переменных, требуемую методомМаксимальная емкость.

таблица локальных переменныхМесто в памяти выделяется во время компиляции и может быть сохраненовремя компиляцииРазличные типы переменных:

  1. базовый тип данных:boolean, byte, char, short, int, float, long, doubleЖдать8своего рода;
  2. тип ссылки на объект:reference, указывая на объектначальный адресизуказатель ссылки;
  3. тип обратного адреса:returnAddressтип обратного адреса.

Переменный слот (Variable Slot):

переменный слотдатаблица локальных переменныхизнаименьшая единица, указанный размер32немного. за64немногоlongиdoubleпеременная, виртуальная машина присваивает ейдва последовательныхизSlotкосмос.

2) Стек операндов

стек операндов(Operand Stack), также известный как стек операций, представляет собой стек по принципу «последним пришел – первым ушел». существуетClassдокументCodeатрибутmax_stacksУказывает максимальную глубину стека во время выполнения.Javaвиртуальная машинаМеханизм выполнения интерпретацииназываетсямеханизм выполнения на основе стека, что относится ккучаозначает-стек операндов.

  1. итаблица локальных переменныхТакой же,стек операндовтакже32длина словаМассив единиц.
  2. Виртуальная машина может быть сохранена в подсчете операторатип данных:int,long,float,double,referenceиreturnTypeТип ожидания (дляbyte,shortа такжеcharЗначение типа также преобразуется вint).
  3. итаблица локальных переменныхОтличие в том, что это не попоказательдля доступа, но через стандартныйоперация стекатолкать стекиПоппосещать. Например, если инструкция помещает значение в стек операндов, другая инструкция может извлечь это значение, чтобы использовать его позже.

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

begin
iload_0    // push the int in local variable 0 onto the stack
iload_1    // push the int in local variable 1 onto the stack
iadd       // pop two ints, add them, push result
istore_2   // pop int, store into local variable 2
end

на этопоследовательность байт-кода, первые две инструкцииiload_0иiload_1будет храниться втаблица локальных переменныхиндекс0и1помещается в стек операндов, за которым следуетiaddИнструкция извлекает два целых числа из стека операндов, складывает их и помещает результат встек операндов. Четвертая директиваistore_2затем изстек операндоввставьте результат и сохраните его втаблица локальных переменныхиндекс2позиция.

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

3) Динамическая ссылка

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

Classдокументпостоянный пулСуществует большое количествоСимволическая ссылка, в байт-кодеинструкция вызова методаПринять направленный на метод постоянного бассейнаСимволическая ссылкаявляется параметром. Эти символы относятся к:

  1. Статический анализ: часть его будет вэтап загрузки классаили при первом использовании он преобразуется впрямая цитата(какfinal,staticдомен и т. д.), называемыйстатический анализ,
  2. Динамический разбор: другая часть будетво время операциипреобразоваться впрямая цитата, называетсядинамическая ссылка.
4) Адрес возврата метода

Когда метод начинает выполняться, есть только два способа выйти из текущего метода:

  1. нормальная доходность: Когда выполнение встречает инструкцию возврата, возвращаемое значение будет передано вышестоящему вызывающему методу.Этот метод выхода вызываетсяЗавершите экспорт в обычном режиме(Normal Method Invocation Completion), в общем,PCприлавокМожет использоваться как обратный адрес.
  2. возврат исключения: при выполнении исключения метод и текущее тело не обрабатываются, это приведет к выходу из метода, а затем нет возвращаемого значения, вызываемогоЭкспорт аварийного завершения(Abrupt Method Invocation Completion), обратный адрес должен быть передан черезобработчик исключенийтаблица для определения.

Когда метод возвращается, следующее может произойти в последовательности3операции:

  1. восстанавливатьсяМетод верхнего уровняизтаблица локальных переменныхистек операндов.
  2. Пучоквозвращаемое значениезапихивать вКадр стека Callorизстек операндов.
  3. будетPCприлавокзначение указывает наследующийМестоположение Директива Местоположение.

резюме:

Уведомление: В Спецификации виртуальной машины Java для этой области указаны два исключения.один: если глубина стека, запрошенная текущим потоком, превышает глубину, разрешенную стеком виртуальной машины,StackOverflowErrorИсключение (в случае, когда стек виртуальной машины не допускает динамического расширения);Второй: Если расширение не может примениться к достаточному объему памяти, оно выдастOutOfMemoryErrorаномальный.

1.3 Стек собственных методов

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

Некоторые версии выпуска виртуальных машин (например,Sun HotSpotвиртуальная машина) напрямуюсобственный стек методовиJavaвиртуальная машинаСтеки два в одном. Как и стек виртуальной машины, собственный стек методов также создаетStackOverflowErrorиOutOfMemoryErrorаномальный.

1.4. Кучи

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

существуетJava, куча делится на две отдельные области:Кайнозой (Young Generation),старость (Old Generation).Кайнозой (Young) делится на три области:ОдинEdenРайон идваSurvivorПлощадь -From SurvivorРайон иTo SurvivorПлощадь.

Краткое резюме: новые объекты размещаются первыми в молодом поколении (Young Generation) изEdenокруг,SurvivorРайон какEdenРайон иOldбуфер области, вSurvivorОбъекты в районе, пережившие несколько коллекций, будут переданы старому поколению.Oldсередина.

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

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

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

1.6 Пул констант времени выполнения

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

1.7 Прямая память

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

(2) Общие исключения переполнения памяти

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

2.1 Переполнение кучи Java

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

настраиватьJVMПараметры запуска:-Xms20Mустановить кучуМинимум памятиза20M,-Xmx20Mустановить кучуМаксимальная памятьиМинимум памятито же, это предотвращаетJavaКуча закончилась памятиАвтоматическое расширение.-XX:+HeapDumpOnOutOfMemoryErrorПараметр может сделать виртуальную машину в исключении переполнения памятиDumpвнекуча памятиМоментальные снимки времени выполнения.

HeapOOM.java

/**
 * VM Args: -Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
 */
public class HeapOOM {
    public static class OOMObject {
    }

    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<>();
        while (true) {
            list.add(new OOMObject());
        }
    }
}

Результаты тестового запуска:

ОткрытымJava VisualVMэкспортHeapвремя выполнения памятиdumpдокумент.

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

Анализ: В этом случае обычно необходимо учитыватьутечка памятиипереполнение памятиДве возможности.

  • Если это утечка памяти:

дальнейшее использованиеJava VisualVMинструменты для анализа, просмотрпросочившийся объектчерез что路径иGC Rootsотносится куборщик мусоране может быть переработан.

  • В случае переполнения памяти:

пройти черезJava VisualVMАнализ инструмента, нет протекающего объекта, то естькуча памятиОбъекты должны выжить. Следует рассмотреть следующие меры:

  1. Проверить существование какого-либо объекта из кодажизненный цикл слишком длинный,Устойчивое состояние слишком долгослучае попробуйте уменьшить память времени выполнения программы.
  2. Проверьте виртуальную машинупараметры кучи(-Xmxи-Xms), по сравнению с машинойфизическая памятьПосмотрите, можно ли его масштабировать.

2.2 Виртуальная машина и переполнение стека нативных методов

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

  • По запросу на сайтеглубина стекабольше, чем позволяет виртуальная машинамаксимальная глубина, броситStackOverflowErrorаномальный.
  • Если виртуальная машинаСтек расширенийне может подать заявку на достаточноОЗУпространство, может броситьOutOfMemoryErrorаномальный.

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

Исключение StackOverflowError

План испытаний один:

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

настраиватьJVMПараметры запуска:-Xss128kнастраиватьстек памятиРазмер128k.

JavaVMStackSOF.java

/**
 * VM Args: -Xss128k
 */
public class JavaVMStackSOF {
    private int stackLength = 1;

    private void stackLeak() {
        stackLength++;
        stackLeak();
    }

    public static void main(String[] args) {
        JavaVMStackSOF oom = new JavaVMStackSOF();
        try {
            oom.stackLeak();
        } catch (Throwable e) {
            System.out.println("Stack length: " + oom.stackLength);
            throw e;
        }
    }
}

Результаты теста:

Анализ: В рамках одного потока либокадр стека слишком великвсе ещеЕмкость стека виртуальной машины слишком мала, когда память не может быть выделена, виртуальная машина выдаетStackOverflowErrorаномальный.

Второй план тестирования:

  • продолжай создаватьнитьи держите поток в рабочем состоянии.

JavaVMStackOOM.java

/**
 * VM Args: -Xss2M
 */
public class JavaVMStackOOM {
    private void running() {
        while (true) {
        }
    }

    public void stackLeakByThread() {
        while (true) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    running();
                }
            }).start();
        }
    }

    public static void main(String[] args) {
        JavaVMStackOOM oom = new JavaVMStackOOM();
        oom.stackLeakByThread();
    }
}

Результаты теста:

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread

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

2.3 Разлитая зона метода и время работы бассейна

(1) Тест на переполнение постоянной памяти пула во время выполнения

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

String.intern() — это нативный метод, его функция такова: если в пуле констант строк есть строка объекта String, то напрямую вернуть объект String в пул констант; В противном случае поместите строку, содержащуюся в этом объекте String, в пул констант и верните ссылку на этот объект String.

настраиватьJVMПараметры запуска: пройти-XX:PermSize=10Mи-XX:MaxPermSize=10Mограничениеобласть методаразмер10M, тем самым косвенно ограничиваяпостоянный пулемкость.

RuntimeConstantPoolOOM.java

/**
 * VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
 */
public class RuntimeConstantPoolOOM {

    public static void main(String[] args) {
        // 使用List保持着常量池的引用,避免Full GC回收常量池
        List<String> list = new ArrayList<>();
        // 10MB的PermSize在Integer范围内足够产生OOM了
        int i = 0;
        while (true) {
            list.add(String.valueOf(i++).intern());
        }
    }
}

Анализ результатов испытаний:

JDK1.6Результаты запуска версии:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
    at java.lang.String.intern(Native Method)

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

(2) Тест на переполнение памяти области метода

область методаClassсоответствующую информацию, такую ​​какимя класса,модификатор доступа,постоянный пул,описание поля,Описание методаЖдать. заПереполнение памяти в области методаОсновная идея состоит в том, чтобы генерировать большое количествобайт-код классазаполнение областиобласть метода.

импортировать сюдаSpringобрамленныйCGLibдинамический прокситехнология байт-кода, через цикл, чтобы постоянно генерировать новыепрокси-класс,достигатьобласть методаЭффект переполнения памяти.

JavaMethodAreaOOM.java

/**
 * VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
 */
public class JavaMethodAreaOOM {

    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                    return proxy.invokeSuper(obj, args);
                }
            });

            enhancer.create();
        }
    }

    private static class OOMObject {
        public OOMObject() {
        }
    }
}

JDK1.6Результаты запуска версии:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:616)

Анализ результатов испытаний:

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

2.4. Прямое переполнение памяти

роднойпрямая памятьемкость может проходить через-XX:MaxDirectMemorySizeуказан, если не указан, то значение по умолчанию такое же, какJavaкучамаксимальное значение(указан -Xmx) то же самое.

сценарии тестирования:

Получено непосредственно через отражениеUnsafeПример применения к операционной системе для выделения памяти посредством отражения:

настраиватьJVMПараметры запуска:-Xmx20MуточнитьJavaмаксимальная память кучи,-XX:MaxDirectMemorySize=10Mуточнитьпрямая памятьразмер.

DirectMemoryOOM.java

/**
 * VM Args: -Xmx20M -XX:MaxDirectMemorySize=10M
 */
public class DirectMemoryOOM {

    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) throws Exception {
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while (true) {
            unsafe.allocateMemory(_1MB);
        }
    }
}

Результаты теста:

Анализ результатов испытаний:

Зависит отDirectMemoryВозникающее в результате переполнение памяти, очевидной особенностью являетсяHeap DumpВ файле не будет видно никакой очевидной информации об исключении. еслиOOMпосле того, как это случилосьDumpФайл небольшой и используется прямо или косвенно в программеNIO, то можете рассмотреть этот вопрос.


Добро пожаловать в технический публичный аккаунт: Zero One Technology Stack

零壹技术栈

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