Исследование процессов внутри виртуальной машины Java | Статья в журнале «Молодой ученый»

Отправьте статью сегодня! Журнал выйдет 28 декабря, печатный экземпляр отправим 1 января.

Опубликовать статью в журнале

Автор:

Рубрика: Информационные технологии

Опубликовано в Молодой учёный №20 (310) май 2020 г.

Дата публикации: 13.05.2020

Статья просмотрена: 280 раз

Библиографическое описание:

Наливайко, А. С. Исследование процессов внутри виртуальной машины Java / А. С. Наливайко. — Текст : непосредственный // Молодой ученый. — 2020. — № 20 (310). — С. 43-46. — URL: https://moluch.ru/archive/310/69986/ (дата обращения: 19.12.2024).



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

Ключевые слова: java, JVM, класс, виртуальная машина, загрузчик классов, память, операционная система, сборка мусора, спецификация.

Java — не просто язык программирования, а целая программная платформа с широкими возможностями. Основная особенность данного языка является в том, что компилятор выдает не машинный код, а так называемый байт-код — оптимизированный набор инструкций, интерпретируемый в среде виртуальной машины Java (Java Virtual Machine — JVM). Трансляция программы Java в байт-код значительно упрощает её выполнение на различных аппаратных и программных платформах, поскольку в каждой среде требуется реализовать только виртуальную машину JVM [1].

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

У JVM есть три составляющих:

1) Спецификация. Первая часть JVM — спецификация программного обеспечения, в которой не определены детали реализации JVM, чтобы обеспечить максимальную свободу творчества при ее создании. Таким образом, все что JVM должна делать, это корректно запускать Java программы;

2) Реализация. Реализация спецификации JVM — это готовая JVM. Существует множество различных реализаций JVM как коммерческих, так и с открытым исходным кодом. JVM HotSpot от проекта OpenJDK является эталонной реализацией и содержит наиболее тщательно проверенную в мире кодовых баз. HotSpot также является самой широко используемой JVM.

Почти все лицензированные JVM созданы, как ответвление от OpenJDK и HotSpot JVM, включая лицензионный JDK от Oracle. Разработчики, создающие лицензированные продукты на основе OpenJDK, зачастую мотивируются желанием увеличить производительность для определенных операционных систем. Обычно пользователи загружают и устанавливают JVM, как часть среды выполнения Java (JRE).

На момент написания данной статьи, самой лучшей реализацией считается GraalVM [7], благодаря его JIT-компилятору, который также написан на Java (а не на С++, как у аналогичных решений). Это позволяет добиться более быстрого оперирования байтами (без конвертирования в Си-подобный синтаксис, и обратно).

3) Экземпляр. После того, как спецификация JVM реализована и выпущена, как программное обеспечение, её можно загрузить как приложение. Загруженная программа является экземпляром виртуальной машины. У JVM можно запрашивать потребление памяти на сервере, ограничивать её в ресурсах, анализировать логи и т. д.

Выделение памяти для процессов

Наиболее частым действием JVM является проверка использования памяти в куче (heap) и стеке (stack). До Java вся память программы управлялась программистом. В Java же память программ управляется с помощью JVM через процесс, названный сборкой мусора (garbage collector, или, сокращенно — GC), который непрерывно определяет и устраняет неиспользуемую память. Весь процесс происходит внутри работающей JVM.

Зарезервированная память (иногда её называют memory spaces или memory pools) состоит из 5 областей:

1) Eden Space (heap) — в этой области выделятся память под все создаваемые из программы объекты. Большая часть объектов живет недолго (итераторы, временные объекты, используемые внутри методов и т. п.), и удаляются при выполнении сборок мусора это области памяти, не перемещаются в другие области памяти. Когда данная область заполняется (т. е. количество выделенной памяти в этой области превышает некоторый заданный процент), GC выполняет быструю (minor collection) сборку мусора. По сравнению с полной сборкой мусора она занимает мало времени, и затрагивает только эту область памяти — очищает от устаревших объектов Eden Space и перемещает выжившие объекты в следующую область;

2) Survivor Space (heap) — сюда перемещаются объекты из предыдущей, после того как они пережили хотя бы одну сборку мусора. Время от времени долгоживущие объекты из этой области перемещаются в Tenured Space;

3) Tenured (Old) Generation (heap) — здесь скапливаются долгоживущие объекты (крупные высокоуровневые объекты, объекты-одиночки (singleton), менеджеры ресурсов и проч.). Когда заполняется эта область, выполняется полная сборка мусора (full, major collection), которая обрабатывает все созданные JVM объекты;

4) Permanent Generation (stack) — в данной области хранится метаинформация, используемая JVM (используемые классы, методы и т. п.);

5) Code Cache (stack) — эта область используется JVM, когда включена JIT-компиляция, в ней кэшируется скомпилированный платформенно-зависимый код.

Загрузка файлов вJVM

Загрузчик классов Java является частью JVM, которая загружает классы в память и делает их доступными для выполнения. Загрузчики классов используют технику отложенной загрузки (lazy-loading) и кэширования, чтобы сделать загрузку классов максимально эффективной.

В Java используется модель делегирования загрузки классов. Основная идея состоит в том, что у каждого загрузчика классов есть «родительский» загрузчик (один, и только один). Когда происходит загрузка класса, то загрузчик «делегирует» поиск класса своему родителю, перед тем как искать класс самостоятельно. Однако, класс загружается тем загрузчиком, который ближе всего к корню, поскольку право первому загрузить класс всегда предоставляется загрузчику-родителю. Это позволяет загрузчику видеть только классы, загруженные самостоятельно, его родителем или предками. Он не может видеть классы, загруженные дочерними загрузчиками.

Существуют следующие системные классы-загрузчики:

1) Bootstrap Class Loader — базовый загрузчик. Загружает платформенные классы. Он является родителем всех остальных классов и частью платформы;

2) Extension Class Loader — загрузчик расширений, потомок Bootstrap-загрузчика. Загружает классы расширений, которые по умолчанию находятся в каталогах jre, lib, ext;

3) Application Class Loader — системный загрузчик классов из classpath, который является непосредственным потомком Extension Class Loader’a. Он загружает классы из каталогов и jar-файлов, указанных переменной среды CLASSPATH, системным свойством java.class.path или параметром командной строки -classpath;

4) Собственный загрузчик — разработчик приложения может создать собственные загрузчики.

Модель делегирования загрузчиков классов представляет собой граф загрузчиков, которые передают друг другу запросы на загрузку. Корнем в этом графе является Bootstrap-загрузчик.

Загрузчик классов сначала проверяет, не загружался ли данный класс ранее. Если это так, то возвращается тот же класс, который возвращался в прошлый раз (класс, хранящийся в кэше). Если нет, то возможность загрузить класс предоставляется родителю. Эти два шага повторяются рекурсивно в глубину. Если родитель возвращает null (или бросает исключение ClassNotFoundException), тогда загрузчик ищет класс самостоятельно.

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

  1. Загрузка (loading)поиск и импорт бинарных данных для типа по его имени, создание класса или интерфейса из этого бинарного представления;
  2. Связывание (linking) — выполнение верификации, подготовки и, необязательного, разрешения:
    1. Верификация (verification)проверка корректности импортируемого типа;
    2. Подготовка (preparation)выделение памяти для статических переменных класса и инициализация памяти значениями по умолчанию;
    3. Разрешение (resolution)преобразование символьных ссылок типов в прямые ссылки;
  3. Инициализация (initialization)вызов Java-кода, который инициализирует переменные классы их правильными начальными значениями.

Внутреннее содержимое любого файла срасширением class

Рис. 1. Процесс компиляции исходного кода Java

Скомпилированные файлы сохраняются в специальные бинарные файлы с расширением class (далее — *.class-файлы). Для каждого класса, интерфейса, описанных в исходном коде, создается по одному *.class-файлу (это также относится к интерфейсам и вложенным классам). Информация записывается без отступов между последовательными частями информации, все выравнивается по границам байтов. 16-битные и 32-битные значения записываются с помощью двух или четырех последовательных 8-битных байтов.

Внутри специальных бинарных файлов содержится следующая информация [6]:

1) Идентификация. Первые 4 байта всегда содержат значение 0xCAFEBABE, что позволяет идентифицировать виртуальной машине данный файл, относящийся к Java (рис. 2);

Рис. 2. Байт-код скомпилированного файла с указанием на идентификатор

2) Версия файла. Следующие 4 байта содержат мажорную и минорную версию файла (по 2 байта соответственно). Вместе эти номера определяют версию *.class-файла. Если файл имеет основную мажорную версию M или минорную m, то система обозначает эту версию как M.m (рис. 3). Например, Java 8 поддерживает major-версию с 45 (0x2D hex) до 52 (0x34 hex);

Рис. 3. Байт-код скомпилированного файла с указанием на данные о версии

3) Пул констант. Далее располагается информация, представляющих строковые константы, имена классов и интерфейсов, полей, методов, и другие константы, которые есть в структуре *.class-файла и его подструктурах. Каждый элемент пула констант начинается с однобайтового тега, определяющего тип константы;

4) Флаги доступа. Список флагов, которые указывают тип файла (класс, интерфейс и т. д.), область видимости (public, private, и т. д.). Различные флаги, такие как ACC_PUBLIC, ACC_FINAL, ACC_INTERFACE, ACC_ENUM и т. д. описаны в спецификации Java Virtual Machine Specification [5];

5) Thisclass. Ссылка на запись в пуле констант;

6) Superclass. Ссылка на запись в пуле констант;

7) Интерфейсы. Количество интерфейсов, реализованных классом;

8) Количество полей. Количество полей в классе или интерфейсе;

9) Поля. После количества полей следует таблица структур переменной длинны. По одной для каждого поля с описанием типа поля и названия (со ссылкой на пул констант);

10) Количество методов. Количество методов в классе или интерфейсе. Это число включает только методы, которые явно определены в классе, без методов, унаследованных от суперклассов;

11) Методы. Далее находятся сами методы. Для каждого метода содержится следующая информация: дескриптор метода (тип возвращаемого значения и список аргументов), количество слов, необходимых для локальных переменных метода, максимальное количество слов стека, необходимых для стека операндов метода, таблицу исключений, перехватываемых методом, байт-коды метода и таблица номеров строк;

12) Количество атрибутов. Количество атрибутов в этом классе, интерфейсе, модуле;

13) Атрибуты. После количества атрибутов следуют таблицы или структуры переменной длинны, описывающие каждый атрибут. Например, всегда есть атрибут «SourceFile». Он содержит имя исходного файла, из которого был скомпилирован class-файл.

Литература:

  1. Николаев В. В., Манеев К. И. АСПЕКТЫ ИНФОРМАЦИОННОЙ БЕЗОПАСНОСТИ ПРИ ПРОГРАММИРОВАНИИ НА ЯЗЫКЕ JAVA // Наука вчера, сегодня, завтра: сб. ст. по матер. XLVIII междунар. науч.-практ. конф. № 7(41). — Новосибирск: СибАК, 2017. — С. 11–15.
  2. Matthew Tyson. What is the JVM? Introducing the Java Virtual Machine // JavaWorld. [Электронный ресурс]. — Режим доступа: https://www.javaworld.com/article/3272244/what-is-the-jvm-introducing-the-java-virtual-machine.html.
  3. Prateek Saini. Java Virtual Machine (JVM) Internals, Part 1 — Classloader // Medium — Get smarter about what matters to you. [Электронный ресурс]. — Режим доступа: https://medium.com/javarevisited/java-virtual-machine-internals-class-loader-eea706eb37d9.
  4. Prateek Saini. Java Virtual Machine (JVM) Internals, Part 2 — Class file format // Medium — Get smarter about what matters to you. [Электронный ресурс]. — Режим доступа: https://medium.com/javarevisited/java-virtual-machine-jvm-internals-part-2-class-file-format-7752e5f7dbbe.
  5. Tim Lindholm, Frank Yellin, Gilad Bracha, Alex Buckley. The Java® Virtual Machine Specification. Java SE 8 Edition [Электронный ресурс]. — Режим доступа: https://docs.oracle.com/javase/specs/jvms/se8/html/index.html.
  6. Java class File // Wikipedia [Электронный ресурс]. — Режим доступа: https://en.wikipedia.org/wiki/Java_class_file.
  7. URL: https://www.graalvm.org/docs/
Основные термины (генерируются автоматически): JVM, класс, виртуальная машина, загрузчик классов, пул констант, сборка мусора, интерфейс, область, область памяти, исходный код.


Ключевые слова

класс, память, операционная система, Java, JVM, виртуальная машина, загрузчик классов, сборка мусора, спецификация

Похожие статьи

Диагностика утечек памяти в Java-приложениях

Данная статья описывает структуру хранения используемой памяти, простые способы диагностики её утечек и временные исправления их.

Абстрактные и динамически сгенерированные контроллеры в ASP.NET

В данной статье будет рассмотрен подход автоматически сгенерированных контроллеров в одной из самых популярных технологий для написания веб-сайтов — ASP.NET Core MVC.

Работа с элементами GUI на примере приложения с использованием кроссплатформенного фреймворка Qt

В статье подробно разобран код приложения, написанного с использованием кроссплатформенного фреймворка Qt основанного на языке C++. Приложение Dynamic Layouts является одним из примеров, входящих в пакет Qt Creator. На примере данного приложения расс...

Разработка алгоритма валидации форм на клиентской стороне для передачи данных

В данной статье рассмотрены методы и алгоритмы функционирования систем клиент-серверной архитектуры для передачи данных с помощью технологий программных инструментов: HTML, CSS, Javascript.

Контейнеризация как современный способ виртуализации

В данной статье рассматривается контейнеризация как эффективный способ виртуализации для различных приложений (сервисов). Также приведен пример создания простейшего dokcer контейнера.

Разработка командной оболочки с поддержкой конвейера (pipeline)

В данной статье говорится об особенностях разработки командной оболочки (shell) для UNIX систем. Приводятся блок-схемы работы основных алгоритмов работы командной оболочки. Подробно разбирается реализация конвейера (pipeline).

Исследование преобразования формул в MathML

В статье рассматривается язык разметки MathML, а также алгоритмы его преобразования.

Технология ASP.NET MVC

В статье рассматривается проектирование архитектуры приложений ASP.NET MVC. Авторы описывают теоретические основы ASP.NET MVC, которые необходимы для разработки web-приложений платформы.NET Framework.

Введение в контейнеры, виртуальные машины и docker

В данной статье рассмотрены виртуальные машины, контейнеры и docker, их архитектуры и отличительные способности.

Разработка программы расписания поездов на основе библиотеки MFC и объектно ориентированного подхода

Статья посвящена описанию процесса проектирования и разработки программы, которая должна отображать расписание поездов в виде строк с данными, а также оставшееся время до отбытия, обновляющееся в реальном времени. на основе библиотеки MFC в Visual C+...

Похожие статьи

Диагностика утечек памяти в Java-приложениях

Данная статья описывает структуру хранения используемой памяти, простые способы диагностики её утечек и временные исправления их.

Абстрактные и динамически сгенерированные контроллеры в ASP.NET

В данной статье будет рассмотрен подход автоматически сгенерированных контроллеров в одной из самых популярных технологий для написания веб-сайтов — ASP.NET Core MVC.

Работа с элементами GUI на примере приложения с использованием кроссплатформенного фреймворка Qt

В статье подробно разобран код приложения, написанного с использованием кроссплатформенного фреймворка Qt основанного на языке C++. Приложение Dynamic Layouts является одним из примеров, входящих в пакет Qt Creator. На примере данного приложения расс...

Разработка алгоритма валидации форм на клиентской стороне для передачи данных

В данной статье рассмотрены методы и алгоритмы функционирования систем клиент-серверной архитектуры для передачи данных с помощью технологий программных инструментов: HTML, CSS, Javascript.

Контейнеризация как современный способ виртуализации

В данной статье рассматривается контейнеризация как эффективный способ виртуализации для различных приложений (сервисов). Также приведен пример создания простейшего dokcer контейнера.

Разработка командной оболочки с поддержкой конвейера (pipeline)

В данной статье говорится об особенностях разработки командной оболочки (shell) для UNIX систем. Приводятся блок-схемы работы основных алгоритмов работы командной оболочки. Подробно разбирается реализация конвейера (pipeline).

Исследование преобразования формул в MathML

В статье рассматривается язык разметки MathML, а также алгоритмы его преобразования.

Технология ASP.NET MVC

В статье рассматривается проектирование архитектуры приложений ASP.NET MVC. Авторы описывают теоретические основы ASP.NET MVC, которые необходимы для разработки web-приложений платформы.NET Framework.

Введение в контейнеры, виртуальные машины и docker

В данной статье рассмотрены виртуальные машины, контейнеры и docker, их архитектуры и отличительные способности.

Разработка программы расписания поездов на основе библиотеки MFC и объектно ориентированного подхода

Статья посвящена описанию процесса проектирования и разработки программы, которая должна отображать расписание поездов в виде строк с данными, а также оставшееся время до отбытия, обновляющееся в реальном времени. на основе библиотеки MFC в Visual C+...

Задать вопрос