Открыть сервис

Виртуальная машина 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 →