JVM Flashcards
За что отвечает JVM?
JVM отвечает за загрузку, проверку и исполнение байт-кода, предоставляет среду выполнения для управления Java-кодом. Управляет памятью и сборкой мусора. Работает с примитивными и ссылочными типами данных. Примитивы включают целые числа и числа с плавающей точкой, а ссылочные типы включают классы, массивы и интерфейсы. JVM является 32-битной машиной, но поддерживает 64-битные типы. Виртуальная машина обеспечивает независимость от операционной системы, позволяя запускать код на любой ОС.
Classloader
Classloader - часть JRE, динамически загружает Java классы в JVM. Загружает классы по запросу, обеспечивая независимость от файлов и файловых систем. Три загрузчика при запуске JVM: Bootstrap class loader, Extensions class loader, System class loader. Bootstrap загружает основные библиотеки, Extensions - код из каталогов расширений, System - код из переменной среды CLASSPATH. Загрузчик классов выполняет загрузку, связывание и проверку. Пользовательские загрузчики классов могут загружать/выгружать классы, изменять способ загрузки байт-кода и модифицировать загруженный байт-код. Они имеют родительские загрузчики, позволяя коммуникацию между пространствами имен.
Области данных времени выполнения
Области данных времени выполнения в JVM:
- PC Register (PCR): Регистр PC для каждого потока, хранящий адрес текущей инструкции JVM.
- Java Virtual Machine Stacks: Стек для каждого потока, содержащий frames. Размер стека может быть фиксированным или динамически расширяемым.
- Heap: Общая область памяти для всех потоков, выделяемая для экземпляров и массивов классов. Управляется сборщиком мусора.
- Method Area: Общая область для всех потоков, хранящая структуры классов, код методов, данные полей и другие элементы. Может быть расширена и уменьшена по мере необходимости.
- Run-Time Constant Pool: Содержит константы для каждого класса в рантайме, представленные в *.class файле. Используется для разрешения ссылок во время выполнения.
- Native Method Stacks: Используются для поддержки native methods, написанных на языке, отличном от Java. Обычно используются стеки Си.
Каждая область данных имеет свою специфическую роль и создается/уничтожается в определенные моменты времени во время выполнения программы.
Frames
Frame в JVM используется для хранения данных, результатов и выполнения динамического связывания. Он создается при вызове метода и уничтожается при завершении вызова метода, будь то нормальное завершение или выбрасывание исключения. У каждого потока есть только один активный frame в любой момент времени.
Основные аспекты frame:
- Локальные переменные: Массив переменных, доступ к которым осуществляется по индексу. Хранит параметры метода, ссылки на объекты и промежуточные результаты.
- Стек операндов: LIFO-стек, используемый для операций, таких как загрузка, выгрузка и арифметические операции. Максимальная глубина определяется во время компиляции.
- Run-Time Constant Pool: Ссылка на пул констант текущего метода, используемая для динамического связывания. Содержит символические ссылки, которые преобразуются в конкретные ссылки во время выполнения.
Жизненный цикл frame:
- Создание: Каждый вызов метода порождает новый frame.
- Активность: Только один frame активен в любой момент времени в потоке управления.
- Завершение: Frame уничтожается по завершении вызова метода, будь то нормальное или резкое завершение.
Нормальное завершение вызова метода:
- Завершается нормально, если не вызывается исключение.
- Значение, если оно есть, возвращается вызывающему методу.
- Текущий frame используется для восстановления состояния инициатора.
Резкое завершение вызова метода:
- Завершается преждевременно при выбрасывании исключения.
- Вызывающему методу не возвращается значение.
- Приводит к неожиданному завершению вызова метода.
Frame обеспечивает разделение данных между вызовами методов, поддерживает динамическое связывание и управляет передачей параметров и возвращаемыми значениями.
Execution Engine
Execution Engine виртуальной машины Java (JVM) выполняет байт-код, который хранится в run-time data areas. Есть два основных компонента Execution Engine: интерпретатор и JIT-компилятор.
Интерпретатор:
- Быстро интерпретирует байт-код.
- Медленнее по сравнению с JIT-компилятором.
- Недостаток в том, что при повторных вызовах метода требуется новая интерпретация.
JIT Compiler (Just-In-Time Compiler):
- Исправляет недостатки интерпретатора.
- Использует интерпретатор для преобразования байт-кода.
- При повторных вызовах метода использует JIT-компилятор, который компилирует весь байт-код в нативный код.
- Улучшает производительность системы.
Дополнительные компоненты:
- Генератор промежуточного кода (Intermediate Code Generator): Производит промежуточный код.
- Code Optimizer: Оптимизирует промежуточный код, сгенерированный выше.
- Генератор целевого кода (Target Code Generator): Генерирует машинный код или родной код.
- Профилировщик (Profiler): Ищет “горячие точки”, т.е. методы, вызываемые несколько раз.
Garbage Collector (Сборщик мусора): Это также важный компонент Execution Engine, отвечающий за управление памятью. Он освобождает память, занимаемую объектами, которые больше не используются программой.
Все эти компоненты работают вместе для эффективного выполнения Java-программы, обеспечивая баланс между быстродействием и оптимизацией кода.