Виртуальная машина Java¶
Виртуальная машина Java (Java Virtual Machine, JVM) — это программное обеспечение, исполняющее байт-код Java и обеспечивающее кроссплатформенность приложений, написанных на языке Java и других языках, компилируемых в байт-код JVM (Kotlin, Scala, Groovy, Clojure). JVM является ключевым компонентом платформы Java (Java Platform, Standard Edition — Java SE), включающей также библиотеки классов (Java API) и среду выполнения (Java Runtime Environment, JRE). Основная функция JVM — абстрагирование от аппаратной платформы и операционной системы: один и тот же байт-код может выполняться на любой системе, для которой существует реализация JVM, без перекомпиляции исходного кода.
¶История
Разработка виртуальной машины Java началась в 1991 году в компании Sun Microsystems в рамках проекта Green, возглавляемого Джеймсом Гослингом. Первоначально проект был ориентирован на бытовую электронику и встраиваемые устройства, но в 1995 году был переориентирован на Интернет и веб-приложения. Первая публичная версия JVM была выпущена вместе с Java Development Kit (JDK) 1.0 в январе 1996 года.
В 2006 году Sun Microsystems открыла исходный код основной реализации JVM (HotSpot) под лицензией GPLv2, что привело к появлению проекта OpenJDK. После приобретения Sun Microsystems корпорацией Oracle в 2010 году разработка JVM продолжилась в рамках OpenJDK, а Oracle выпускает коммерческую версию Oracle JDK на основе того же кода. С 2017 года Oracle перешла на шестимесячный цикл выпуска новых версий Java, что ускорило эволюцию JVM.
¶Архитектура
JVM представляет собой абстрактную вычислительную машину, спецификация которой описана в документах Java Virtual Machine Specification. Архитектура JVM включает три основные подсистемы: подсистему загрузки классов (ClassLoader), область памяти (Runtime Data Areas) и исполнительный движок (Execution Engine).
¶Подсистема загрузки классов
ClassLoader отвечает за динамическую загрузку файлов классов (.class) в память JVM. Загрузка происходит по запросу (ленивая загрузка) и включает три этапа: загрузку (поиск и чтение бинарного представления класса), связывание (верификацию, подготовку и разрешение ссылок) и инициализацию (выполнение статических инициализаторов). JVM использует иерархию загрузчиков: Bootstrap ClassLoader (загружает основные классы Java из rt.jar), Extension ClassLoader (загружает расширения) и Application ClassLoader (загружает классы из classpath).
¶Область памяти
Память JVM разделена на несколько областей:
- Heap (куча) — общая область памяти для всех потоков, в которой размещаются объекты и массивы. Управляется сборщиком мусора. Размер кучи может задаваться параметрами -Xms (начальный размер) и -Xmx (максимальный размер).
- Method Area (область методов) — хранит структуру каждого класса: метаданные, константы, статические переменные, код методов. В HotSpot JVM эта область называется Metaspace (начиная с Java 8) и располагается в нативной памяти, а не в куче.
- Java Stack (стек Java) — для каждого потока создается свой стек, содержащий фреймы (кадры). Каждый фрейм соответствует вызову метода и хранит локальные переменные, стек операндов и ссылки на пул констант.
- PC Register (регистр счетчика команд) — для каждого потока хранит адрес текущей исполняемой инструкции JVM.
- Native Method Stack (стек нативных методов) — поддерживает вызовы нативных методов, написанных на других языках (например, C/C++).
¶Исполнительный движок
Исполнительный движок преобразует байт-код в машинные инструкции. В современных JVM (HotSpot) используется комбинация интерпретации и JIT-компиляции (Just-In-Time). Интерпретатор выполняет байт-код построчно, а JIT-компилятор переводит часто выполняемые участки кода (горячие методы) в нативный машинный код, что значительно ускоряет выполнение. HotSpot использует два уровня компиляции: C1 (клиентский, быстрый) и C2 (серверный, более агрессивная оптимизация). Начиная с Java 9, появился экспериментальный компилятор Graal JIT.
¶Сборка мусора
Управление памятью в JVM осуществляется автоматически через сборку мусора (Garbage Collection, GC). Сборщик мусора определяет объекты, на которые больше нет ссылок, и освобождает занимаемую ими память. JVM предоставляет несколько алгоритмов GC, настраиваемых через параметры командной строки:
- Serial GC — однопоточный сборщик, подходит для небольших приложений с одним ядром процессора.
- Parallel GC (Throughput Collector) — использует несколько потоков для ускорения сборки, ориентирован на максимальную пропускную способность.
- CMS (Concurrent Mark-Sweep) — минимизирует паузы за счет параллельной работы с приложением (устарел, удален в Java 14).
- G1 (Garbage-First) — по умолчанию с Java 9; разделяет кучу на регионы, выполняет сборку с предсказуемыми паузами.
- ZGC (Z Garbage Collector) — экспериментальный сборщик с очень низкими паузами (менее 10 мс), доступен с Java 11.
- Shenandoah — аналогично ZGC, низкие паузы, доступен с Java 12.
¶Версии и реализации
Существует множество реализаций JVM, соответствующих спецификации Java Virtual Machine Specification. Основные из них:
- HotSpot — основная эталонная реализация, разработанная Sun Microsystems (ныне Oracle). Входит в состав OpenJDK и Oracle JDK.
- OpenJ9 — реализация от IBM (ранее IBM J9), открытая в 2017 году под лицензией Eclipse Public License. Отличается меньшим потреблением памяти и быстрым запуском.
- GraalVM — высокопроизводительная виртуальная машина на основе HotSpot, поддерживающая JIT-компиляцию Graal, а также предварительную компиляцию (AOT) и поддержку других языков (JavaScript, Python, Ruby, R).
- Android Runtime (ART) — среда выполнения для Android, которая использует предварительную компиляцию (AOT) и не является полноценной JVM, но исполняет байт-код Java (Dalvik bytecode).
- Microsoft JVM — проприетарная реализация от Microsoft, выпущенная в 1996 году, но после судебного иска Sun в 2001 году была прекращена поддержка.
¶Производительность и оптимизация
Современные JVM достигают высокой производительности благодаря JIT-компиляции, инлайн-разворачиванию методов, устранению мертвого кода, оптимизации циклов и другим техникам. Бенчмарки показывают, что производительность Java-приложений на HotSpot JVM сопоставима с нативными программами на C/C++ для многих задач. Однако JVM имеет накладные расходы на запуск (startup time) и потребление памяти из-за необходимости загрузки классов и управления кучей.
¶Безопасность
JVM обеспечивает несколько уровней безопасности: верификация байт-кода (проверка корректности инструкций и типов), управление доступом к ресурсам через SecurityManager (устарел в Java 17) и изоляция потоков. В версиях Java 8 и более ранних существовала уязвимость, связанная с возможностью выполнения произвольного кода через апплеты, что привело к отказу от технологии апплетов в Java 9.
¶Применение
JVM используется в широком спектре приложений:
- Веб-серверы и серверные приложения — Java Enterprise Edition (Jakarta EE), Spring Framework, Apache Tomcat, WildFly.
- Большие данные — Apache Hadoop, Apache Spark, Apache Flink.
- Мобильные приложения — Android (через ART, но не через JVM напрямую).
- Финансовые системы — высокочастотный трейдинг, банковские системы.
- Научные вычисления — обработка данных, машинное обучение (DL4J, Weka).
- Встраиваемые системы — Java ME (Micro Edition) для устройств с ограниченными ресурсами.
¶Критика
Основные недостатки JVM включают:
- Потребление памяти — JVM по умолчанию резервирует значительный объем оперативной памяти (обычно от 256 МБ), что делает её непригодной для очень маломощных устройств.
- Время запуска — загрузка классов и инициализация JVM может занимать несколько секунд, что критично для микросервисов и контейнерных сред.
- Сложность настройки — для достижения оптимальной производительности требуется тонкая настройка параметров GC, размера кучи и JIT-компиляции.
- Уязвимости безопасности — исторические проблемы с апплетами и десериализацией (например, уязвимость CVE-2015-4852).
¶Интересные факты
- Первая JVM (1996) имела размер около 1 МБ и поддерживала только интерпретацию байт-кода.
- В 2018 году Google выпустила Android Runtime (ART) с поддержкой профильной компиляции (PGO), что улучшило производительность Android-приложений.
- JVM способна выполнять байт-код не только Java, но и других языков: Kotlin, Scala, Groovy, Clojure, JRuby, Jython, а также языков, скомпилированных в байт-код через инструменты вроде GraalVM Polyglot.
- В 2020 году Oracle выпустила Java 15 с поддержкой запечатанных классов (sealed classes) и скрытых классов (hidden classes), расширяющих возможности JVM.
¶Источники
- Java Virtual Machine Specification, Java SE 17 Edition (Oracle, 2021)
- «The Java Virtual Machine: Java SE 8 Edition» — Tim Lindholm, Frank Yellin, Gilad Bracha, Alex Buckley
- OpenJDK Documentation — openjdk.org
- «Java Performance: The Definitive Guide» — Scott Oaks (O'Reilly, 2014)
- Спецификация Java Language Specification, Java SE 17 Edition (Oracle, 2021)
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →


