JVM: что это такое и архитектура
Что такое JVM?
Java Virtual Machine (JVM) — исполнительный движок, запускающий Java-приложения. Она трансформирует скомпилированный Java байт-код в нативные машинные инструкции и выполняет их на любой платформе, поддерживающей JVM. JVM — ключевой компонент Java Runtime Environment (JRE). В отличие от языков, компилируемых сразу в машинный код под конкретную ОС, Java-компилятор производит платформонезависимый байт-код, который JVM интерпретирует или компилирует в runtime.
Как работает JVM
Java-источник сначала компилируется в байт-код, который JVM затем интерпретирует или JIT-компилирует в нативный код. JVM также управляет выделением памяти, планированием потоков и взаимодействием с нативными библиотеками.
В этом туториале вы узнаете:
- Архитектуру JVM
- Процесс компиляции и выполнения программного кода
- Компиляцию и выполнение C-кода
- Компиляцию и выполнение Java-кода в JVM
- Почему Java одновременно компилируемый и интерпретируемый
- Факторы, влияющие на производительность Java
Архитектура JVM
Дизайн JVM модулен, состоит из нескольких подсистем, работающих вместе для загрузки, верификации и выполнения Java-кода.
- Class Loader — загружает файлы классов и выполняет линковку (верификацию, подготовку, разрешение) и инициализацию.
- Method Area — хранит структуры классов, метаданные, пулы констант, код методов.
- Heap — содержит все объекты, переменные экземпляров и массивы. Разделяется между всеми потоками.
- Java Stack — у каждого потока свой стек для локальных переменных и частичных результатов. Новый фрейм создаётся при входе в метод и удаляется при выходе.
- Program Counter (PC) Register — хранит адрес следующей инструкции для каждого потока.
- Native Method Stack — хранит вызовы нативного кода (написанного на C/C++).
- Execution Engine — выполняет байт-код интерпретацией или через JIT-компилятор.
- Native Method Interface (JNI) — позволяет Java-коду вызывать нативные библиотеки.
- Native Libraries — наборы платформозависимого нативного кода, используемые исполнительным движком.
Процесс компиляции и выполнения программного кода
Запуск программы обычно включает шаги:
- Редактор — где пишется исходный код.
- Компилятор — транслирует высокоуровневый код в нативный машинный код или байт-код.
- Линкер — объединяет объектные файлы и разрешает внешние ссылки.
- Загрузчик — загружает итоговый исполняемый файл в память.
- Выполнение — ОС и процессор запускают программу.
Компиляция и выполнение C-кода
Для иллюстрации Java-процесса рассмотрим простую C-программу. Пусть main в a1.c вызывает f1 (в a2.c) и f2 (в a3.c).
Компилятор превращает каждый .c в объектный файл с машинным кодом. Линкер объединяет их в единый .exe. При запуске загрузчик маппит myapp.exe в ОЗУ и ОС начинает выполнение.
Компиляция и выполнение Java-кода в JVM
Java следует похожему, но отличному workflow. Исходники a1.java, a2.java, a3.java компилируются в байт-код a1.class, a2.class, a3.class. Отдельного этапа линковки нет; JVM загружает байт-код по требованию.
Во время выполнения класс-загрузчик JVM вносит классы в память, верифицирует их на безопасность, исполнительный движок интерпретирует или JIT-компилирует байт-код в нативный машинный код. Этот JIT-шаг делает Java одновременно компилируемой и интерпретируемой.
Примечание: JIT-компилятор — ключевой компонент JVM, выполняющий на лету трансляцию горячих путей байт-кода в эффективные нативные инструкции.
Почему Java одновременно компилируемая и интерпретируемая?
Дизайн Java сочетает преимущества обоих подходов:
- Компилятор превращает исходник в байт-код, обеспечивая платформонезависимость.
- JVM интерпретирует или JIT-компилирует байт-код во время выполнения, позволяя динамическую оптимизацию.
- Нативные библиотеки доступны через Java Native Interface (JNI), давая гибкость нативного кода при необходимости.
Почему Java медленнее?
Runtime-накладные расходы Java происходят из двух источников:
- Динамическая линковка — методы разрешаются во время выполнения, а не компиляции, добавляя небольшие накладные расходы на поиск.
- Интерпретация байт-кода во время выполнения — даже с JIT, начальное выполнение байт-кода несёт стоимость конвертации до производства нативного кода.
Современные реализации JVM драматически снизили эти накладные расходы через агрессивную оптимизацию, tiered compilation и аппаратную настройку.
Резюме
- JVM — движок, выполняющий Java байт-код на любой поддерживаемой платформе.
- Её архитектура включает загрузчик классов, области памяти, стеки, PC-регистр, исполнительный движок.
- Java-код компилируется в байт-код, который JVM интерпретирует или JIT-компилирует во время выполнения.
- JIT-компилятор ускоряет выполнение, конвертируя горячие пути байт-кода в нативный машинный код.
- Хотя Java исторически имела проблемы с производительностью, недавние версии JVM в значительной степени их смягчили.
java
- Что такое ЧПУ? Понимание компьютерного числового управления для современного производства
- Java 10: Thread-Local Handshakes для ускорения VM safepoints
- Токарная обработка: ключевой процесс прецизионной механической обработки
- Архитектурное проектирование: принципы, практика и влияние на среду
- Строительные болты (machine bolts): виды, марки прочности, монтаж и крутящий момент
- Прядильные станки: от волокна к нити
- Автоматы с молоком: удобно, доступно, экологично
- Горизонтально-расточные станки: конструкция, работа, применение
- Автоматические прессовые станки: принцип работы, преимущества и применение
- Обслуживание станков (Machine Tending): преимущества, автоматизация и применение