что такое виртуальная машина java

Внутренности JVM, Часть 1 — Загрузчик классов

Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

В этой серии статей я расскажу о том, как работает Java Virtual Machine. Сегодня мы рассмотрим механизм загрузки классов в JVM.

Виртуальная машина Java — это сердце экосистемы Java-технологий. Она делает для Java-программ возможность реализации принципа «написано один раз, работает везде» (write once run everywhere). Как и другие виртуальные машины, JVM представляет собой абстрактный компьютер. Основная задача JVM — загружать class-файлы и выполнять содержащийся в них байт-код.

В состав JVM входят различные компоненты, такие как загрузчик классов (Classloader), сборщик мусора (Garbage Collector) (автоматическое управление памятью), интерпретатор, JIT-компилятор, компоненты управления потоками. В этой статье рассмотрим загрузчик классов (Class loader).

Загрузчик классов загружает class-файлы как для вашего приложения, так и для Java API. В виртуальную машину загружаются только те class-файлы Java API, которые действительно требуются при выполнении программы.

Байт-код выполняется подсистемой исполнения (execution engine).

что такое виртуальная машина java. . что такое виртуальная машина java фото. что такое виртуальная машина java-. картинка что такое виртуальная машина java. картинка . Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Что такое загрузка классов?

Загрузка классов — это поиск и загрузка типов (классов и интерфейсов) динамически во время выполнения программы. Данные о типах находятся в бинарных class-файлах.

Этапы загрузки классов

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

Примечание — загрузчик классов, помимо загрузки классов, также отвечает за поиск ресурсов. Ресурс — это некоторые данные (например, “.class” файл, данные конфигурации, изображения), которые идентифицируются с помощью абстрактного пути, разделенного символом «/». Ресурсы обычно упаковываются вместе с приложением или библиотекой для того, чтобы их можно было использовать в коде приложения или библиотеки.

Механизм загрузки классов в Java

Platform class loader — загружает выбранные (на основе безопасности / разрешений) модули Java SE и JDK. Например, java.sql.

Bootstrap class loader — загружает основные модули Java SE и JDK.

Эти три встроенных загрузчика классов работают вместе следующим образом:

Запустив этот код на установленном у меня Amazon Corretto 11.0.3, получим следующий результат:

Подробнее изучить ClassLoader API вы можете здесь (JDK 11).

Источник

Инструменты для запуска и разработки Java приложений, компиляция, выполнение на JVM

Ни для кого не секрет, что на данный момент Java — один из самых популярных языков программирования в мире. Дата официального выпуска Java — 23 мая 1995 года.

Эта статья посвящена основам основ: в ней изложены базовые особенности языка, которые придутся кстати начинающим “джавистам”, а опытные Java-разработчики смогут освежить свои знания.

* Статья подготовлена на основе доклада Евгения Фраймана — Java разработчика компании IntexSoft.
В статье присутствуют ссылки на внешние материалы
.

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

1. JDK, JRE, JVM

Java Development Kit — комплект разработчика приложений на языке Java. Он включает в себя Java Development Tools и среду выполнения Java — JRE (Java Runtime Environment).

Java development tools включают в себя около 40 различных тулов: javac (компилятор), java (лаунчер для приложений), javap (java class file disassembler), jdb (java debugger) и др.

Среда выполнения JRE — это пакет всего необходимого для запуска скомпилированной Java-программы. Включает в себя виртуальную машину JVM и библиотеку классов Java — Java Class Library.

JVM — это программа, предназначенная для выполнения байт-кода. Первое преимущество JVM — это принцип “Write once, run anywhere”. Он означает, что приложение, написанное на Java, будет работать одинаково на всех платформах. Это является большим преимуществом JVM и самой Java.

До появления Java, многие компьютерные программы были написаны под определенные компьютерные системы, а предпочтение отдавалось ручному управлению памятью, как более эффективному и предсказуемому. Со второй половины 1990-х годов, после появления Java, автоматическое управление памятью стало общей практикой.

Существует множество реализаций JVM, как коммерческих, так и с открытым кодом. Одна из целей создания новых JVM — увеличение производительности для конкретной платформы. Каждая JVM пишется под платформу отдельно, при этом есть возможность написать ее так, чтобы она работала быстрее на конкретной платформе. Самая распространённая реализация JVM — это JVM Hotspot от OpenJDK. Также есть реализации IBM J9, Excelsior JET.

2. Выполнение кода на JVM

Согласно спецификации Java SE, для того, чтобы получить код, работающий в JVM, необходимо выполнить 3 этапа:

3. Загрузчики классов и их иерархия

Вернемся к загрузчикам классов — это специальные классы, которые являются частью JVM. Они загружают классы в память и делают их доступными для выполнения. Загрузчики работают со всеми классами: и с нашими, и с теми, которые непосредственно нужны для Java.

Представьте ситуацию: мы написали свое приложение, и помимо стандартных классов там есть наши классы, и их очень много. Как с этим будет работать JVM? В Java реализована отложенная загрузка классов, иными словами lazy loading. Это значит, что загрузка классов не будет выполняться до тех пор, пока в приложении не встретится обращение к классу.

Иерархия загрузчиков классов

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Первый загрузчик классов — это Bootstrap classloader. Он написан на C++. Это базовый загрузчик, который загружает все системные классы из архива rt.jar. При этом, есть небольшое отличие между загрузкой классов из rt.jar и наших классов: когда JVM загружает классы из rt.jar, она не выполняет все этапы проверки, которые выполняются при загрузке любого другого класс-файла т.к. JVM изначально известно, что все эти классы уже проверены. Поэтому, включать в этот архив какие-либо свои файлы не стоит.

Следующий загрузчик — это Extension classloader. Он загружает классы расширений из папки jre/lib/ext. Допустим, вы хотите, чтобы какой-то класс загружался каждый раз при старте Java машины. Для этого вы можете скопировать исходный файл класса в эту папку, и он будет автоматически загружаться.

Еще один загрузчик — System classloader. Он загружает классы из classpath’а, который мы указали при запуске приложения.

Процесс загрузки классов происходит по иерархии:

4. Структура Сlass-файлов и процесс загрузки

Перейдем непосредственно к структуре Class-файлов.

Все числа, строки, указатели на классы, поля и методы хранятся в Сonstant pool — области памяти Meta space. Описание класса хранится там же и содержит имя, модификаторы, супер-класс, супер-интерфейсы, поля, методы и атрибуты. Атрибуты, в свою очередь, могут содержать любую дополнительную информацию.

Таким образом, при загрузке классов:

5. Исполнение байт-кода на JVM

В первую очередь, для исполнения байт-кода, JVM может его интерпретировать. Интерпретация — довольно медленный процесс. В процессе интерпретации, интерпретатор “бежит” построчно по класс-файлу и переводит его в команды, которые понятны JVM.

Также JVM может его транслировать, т.е. скомпилировать в машинный код, который будет исполняться непосредственно на CPU.

Команды, которые исполняются часто, не будут интерпретироваться, а сразу будут транслироваться.

6. Компиляция

Компилятор — это программа, которая преобразует исходные части программ, написанные на языке программирования высокого уровня, в программу на машинном языке, “понятную” компьютеру.

Компиляторы делятся на:

Также компиляторы могут классифицироваться по моменту компиляции:

7. Организация памяти в Java

Стек — это область памяти в Java, которая работает по схеме LIFO — “Last in — Fisrt Out” или “Последним вошел, первым вышел”.

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

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

Когда вызывается любой метод в Java, создается фрейм или область памяти в стеке, и метод кладется на его вершину. Когда метод завершает выполнение, он удаляется из памяти, тем самым освобождая память для следующих методов. Если память стека будет заполнена, Java бросит исключение java.lang.StackOverFlowError. К примеру, это может произойти, если у нас будет рекурсивная функция, которая будет вызывать сама себя и памяти в стеке не будет хватать.

Ключевые особенности стека:

Куча разбита на несколько более мелких частей, называемых поколениями:

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Почему отказались от Permanent generation? В первую очередь, это из-за ошибки, которая была связана с переполнением области: так как Perm имел константный размер и не мог расширяться динамически, рано или поздно память заканчивалась, кидалась ошибка, и приложение падало.

Meta space же имеет динамический размер, и во время исполнения он может расширяться до размеров памяти JVM.

Ключевые особенности кучи:

Основываясь на информации выше, рассмотрим, как происходит управление памятью на простом примере:

У нас есть класс App, в котором единственный метод main состоит из:

— примитивной переменой id типа int со значением 23
— ссылочной переменной pName типа String со значением Jon
— ссылочной переменной p типа person

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Как уже упоминалось, при вызове метода на вершине стека создаётся область памяти, в которой хранятся данные, необходимые этому методу для выполнения.
В нашем случае, это ссылка на класс person: сам объект хранится в куче, а в стеке хранится ссылка. Также в стек кладется ссылка на строку, а сама строка хранится в куче в String pool. Примитив хранится непосредственно в стеке.

Для вызова конструктора с параметрами Person (String) из метода main() в стеке, поверх предыдущего вызова main() создается в стеке отдельный фрейм, который хранит:

this — ссылка на текущий объект
— примитивное значение id
— ссылочную переменную personName, которая указывает на строку в String Pool.

После того, как мы вызвали конструктор, вызывается setPersonName(), после чего снова создается новый фрейм в стеке, где хранятся те же данные: ссылка на объект, ссылка на строку, значение переменной.

Таким образом, когда выполнится метод setter, фрейм пропадет, стек очистится. Далее выполняется конструктор, очищается фрейм, который был создан под конструктор, после чего метод main() завершает свою работу и тоже удаляется из стека.

Если будут вызваны другие методы, для них будут также созданы новые фреймы с контекстом этих конкретных методов.

8. Garbage collector

В куче работает Garbage collector — программа, работающая на виртуальной машине Java, которая избавляется от объектов, к которым невозможно получить доступ.

Разные JVM могут иметь различные алгоритмы сборки мусора, также существуют разные сборщики мусора.

Мы поговорим о самом простом сборщике Serial GC. Сборку мусора мы запрашиваем при помощи System.gc().

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Как уже было упомянуто выше, куча разбита на 2 области: New generation и Old generation.

New generation (младшее поколение) включает в себя 3 региона: Eden, Survivor 0 и Survivor 1.

Old generation включает в себя регион Tenured.

Что происходит, когда мы создаем в Java объект?

В первую очередь объект попадает в Eden. Если мы создали уже много объектов и в Eden уже нет места, срабатывает сборщик мусора и освобождает память. Это, так называемая, малая сборка мусора — на первом проходе он очищает область Eden и кладёт “выжившие” объекты в регион Survivor 0. Таким образом регион Eden полностью высвобождается.

Если произошло так, что область Eden снова была заполнена, garbage collector начинает работу с областью Eden и областью Survivor 0, которая занята на данный момент. После очищения выжившие объекты попадут в другой регион — Survivor 1, а два остальных останутся чистыми. При последующей сборке мусора в качестве региона назначения опять будет выбран Survivor 0. Именно поэтому важно, чтобы один из регионов Survivor всегда был пустым.

JVM следит за объектами, которые постоянно копируются и перемещаются из одного региона в другой. И для того, чтобы оптимизировать данный механизм, после определённого порога сборщик мусора перемещает такие объекты в регион Tenured.

Когда в Tenured места для новых объектов не хватает, происходит полная сборка мусора — Mark-Sweep-Compact.

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Во время этого механизма определяется, какие объекты больше не используются, регион очищается от этих объектов, и область памяти Tenured дефрагментируется, т.е. последовательно заполняется нужными объектами.

Источник

Варим байткод на кухне JVM

Меня зовут Александр Коцюруба, я руковожу разработкой внутренних сервисов в компании ДомКлик. Многим разработчикам, пишущим на Java, с опытом приходит понимание внутреннего устройства JVM. Чтобы облегчить этот путь Java-самурая, я решил простым языком изложить основы виртуальной машины Java (JVM) и работы с байткодом.

Что такое таинственный байткод и где он обитает?

Постараюсь ответить на этот вопрос на примере приготовления солений.

что такое виртуальная машина java. e7qk0ed8rejsgfy30aaosw8yrya. что такое виртуальная машина java фото. что такое виртуальная машина java-e7qk0ed8rejsgfy30aaosw8yrya. картинка что такое виртуальная машина java. картинка e7qk0ed8rejsgfy30aaosw8yrya. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Зачем нужен JVM и байткод?

JVM возникла под лозунгом Write Once Run Anywhere (WORA) в стенах компании Sun Microsystems. В отличие от концепции Write Once Compile Anywhere (WOCA), WORA подразумевает наличие виртуальной машины для каждой ОС, которая исполняет единожды скомпилированный код (байткод).

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Write Once Run Anywhere (WORA)

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Write Once Compile Anywhere (WOCA)

JVM и байткод лежат в основе концепции WORA и избавляют нас от нюансов и необходимости компиляции под каждую ОС.

Байткод

Чтобы понять, что из себя представляет байткод, давайте рассмотрим пример. Конечно, этот код не делает ничего полезного, он только послужит для дальнейшего разбора.

На первый взгляд — непонятный набор инструкций. Чтобы разобраться, как и с чем они работают, необходимо будет погрузиться во внутреннюю кухню JVM.

Кухня JVM

Посмотрим на JVM runtime memory:

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Можно сказать, что JVM — наша кухня. Далее рассмотрим остальных участников:

Method area — Кулинарная книга

что такое виртуальная машина java. ism v2gh1keewv8lsjhoni3g vg. что такое виртуальная машина java фото. что такое виртуальная машина java-ism v2gh1keewv8lsjhoni3g vg. картинка что такое виртуальная машина java. картинка ism v2gh1keewv8lsjhoni3g vg. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

В области Method area хранится скомпилированный код для каждой функции. Когда поток начинает выполнять функцию, в общем случае он получает инструкции из этой области. По сути, она представляет собой кулинарную книгу рецептов, где подробно описано, как приготовить всё подряд, начиная от яичницы и заканчивая каталонской сарсуэлой.

Thread 1..N — Команда поваров

что такое виртуальная машина java. . что такое виртуальная машина java фото. что такое виртуальная машина java-. картинка что такое виртуальная машина java. картинка . Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Потоки строго выполняют предписанные им инструкции (method area), для этого у них есть PC Register и JVM Stack. Можно сравнить каждый поток с поваром, который выполняет данное ему поручение, в точности следуя рецептам из кулинарной книги.

PC Register — Заметки на полях

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Program Counter Register — счетчик команд нашего потока. Хранит в себе адрес выполняемой инструкции. На кухне это были бы некие заметки, на какой странице кулинарной книги мы сейчас находимся.

JVM Stack

Стек фреймов. Под каждую функцию выделяется фрейм, в рамках которого текущий поток работает с переменными и операндами. В рамках аналогии с приготовлением наших солений это мог бы быть набор вложенных операций:

Frame — Рабочий стол

что такое виртуальная машина java. ti3kfyzgveqkh726jelzbedkpvk. что такое виртуальная машина java фото. что такое виртуальная машина java-ti3kfyzgveqkh726jelzbedkpvk. картинка что такое виртуальная машина java. картинка ti3kfyzgveqkh726jelzbedkpvk. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

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

Local variables — Подписанные контейнеры

что такое виртуальная машина java. tlasrl j3ocbkzd irebk0usgsu. что такое виртуальная машина java фото. что такое виртуальная машина java-tlasrl j3ocbkzd irebk0usgsu. картинка что такое виртуальная машина java. картинка tlasrl j3ocbkzd irebk0usgsu. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Это массив локальных переменных (local variable table), который, как следует из названия, хранит значения, тип и область видимости локальных переменных. Это похоже на подписанные контейнеры, куда можно складывать промежуточные результаты профессиональной деятельности.

Operand stack — Разделочная доска

что такое виртуальная машина java. ic90m1h3sbynrbt. что такое виртуальная машина java фото. что такое виртуальная машина java-ic90m1h3sbynrbt. картинка что такое виртуальная машина java. картинка ic90m1h3sbynrbt. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Operand stack хранит аргументы для инструкций JVM. Например, целочисленные значения для операции сложения, ссылки на объекты heap и т. п.

Самый близкий пример, который я могу привести — разделочная доска, на которой помидор и огурец в один момент превращаются в салат. В отличие от local variables на доску мы кладем только то, с чем будем выполнять ближайшую инструкцию.

Heap — Стол раздачи

что такое виртуальная машина java. . что такое виртуальная машина java фото. что такое виртуальная машина java-. картинка что такое виртуальная машина java. картинка . Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

В рамках работы с фреймом мы оперируем ссылками на объекты, сами же объекты хранятся в heap. Важное отличие в том, что фрейм принадлежит только одному потоку, и локальные переменные «живут», пока жив фрейм (выполняется функция). А heap доступен и другим потокам, и живет до включения сборщика мусора. По аналогии с кухней, можно привести пример со столом раздачи, который один и является общим. И чистит его отдельная команда уборщиков.

JVM-кухня. Взгляд изнутри. Работа с Frame

Разберем для начала функцию warmUp :

Дизассемблированный байткод функции:

Инициализация фрейма — Подготовка рабочего места

Для выполнения этой функции в JVM stack потока будет создан frame. Напомню, что стек состоит из массива local variables и operand stack.

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Начало исполнения инструкций

Чтобы понять, как происходит работа с фреймом, достаточно вооружиться списком инструкций JVM (Java bytecode instruction listings) и пошагово разобрать метку L0 :

ICONST_1 — добавляем 1 (Int) в operand stack:

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

ISTORE 2 — pull значения (с типом Int) из operand stack и запись в local variables с индексом 2:

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

ILOAD 1 — загрузить значение из local variables с индексом 1 в operand stack:

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

ISTORE 3 — pull значения (с типом Int) из operand stack и запись в local variables с индексом 3:

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

ILOAD 2 — загрузить значение из local variables с индексом 2 в operand stack.

ILOAD 3 — загрузить значение из local variables с индексом 3 в operand stack:

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

Вот как выглядели бы эти строчки байткода на Java:

Проводя аналогию с кухней, эту функцию можно описать как задачу для повара «кипяти воду 10 минут». Далее наш профессионал своего дела:

JVM-кухня. Взгляд изнутри. Работа с Heap

NEW java/lang/Object — выделение памяти под объект класса Object из heap. В стек будет помещен не сам объект, а ссылка на него в heap:

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

DUP — дублирование «верхнего» элемента стека. Одна ссылка нужна для иницализации объекта, вторая для ее сохранения в local variables:

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

INVOKESPECIAL java/lang/Object. ()V — инициализация объекта соответствующего класса ( Object ) по ссылке из стека:

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

ASTORE 3 — последний шаг, сохранение ссылки на объект в local variables с индексом 3.

Проводя аналогию с кухней, создание объекта класса я бы сравнил с приготовлением на общем столе (heap). Для этого необходимо выделить себе достаточно места на столе раздачи, вернуться на рабочее место и кинуть записку с адресом (reference) в соответствующий контейнер (local variables). И только после этого начать создавать объект класса.

JVM-кухня. Взгляд изнутри. Многопоточность

Теперь рассмотрим такой пример:

Дизассемблированный байткод выглядит так:

Состояние нашего operand stack по ходу выполнения инструкций:

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

При работе в один поток всё будет выполняться корректно. Если же потоков будет несколько, то может возникнуть следующая проблема. Представим, что оба потока одновременно получили значение поля ingredientsCount и записали его в стек. Тогда состояние operand stack и поля ingredientsCount может выглядеть так:

что такое виртуальная машина java. image loader. что такое виртуальная машина java фото. что такое виртуальная машина java-image loader. картинка что такое виртуальная машина java. картинка image loader. Перевод статьи подготовлен специально для студентов курса «Разработчик Java».

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

Чтобы избежать таких ситуаций, существуют разные инструменты вроде блокировок, thread-safety функций и т.д.

Подводя итоги

Крайне редко у разработчика возникает потребность лезть в байткод, если только это не является спецификой его работы. В то же время, понимание работы байткода помогает лучше понять многопоточность и преимущества того или иного языка, а также помогает дальше расти профессионально.

Стоит отметить, что это далеко не все части JVM. Есть еще много интересных «штук», например, constant pool, bytecode verifier, JIT, code cache и т.д. Но чтобы не перегружать статью, я сосредоточился только на тех элементах, которые необходимы для общего понимания.

Источник

Как написать (игрушечную) JVM

Статья про KVM оказалась интересной для читателей, поэтому сегодня публикуем новый перевод статьи Serge Zaitsev: как работает Java Virtual Machine под капотом.

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

Я попытаюсь написать игрушечную (и неполную) JVM, чтобы показать основные принципы ее работы. Надеюсь, эта статья вызовет у вас интерес и вдохновит на дальнейшее изучение JVM.

Наша скромная цель

Мы компилируем наш класс с javac Add.java, и в результате получается Add.class. Этот class файл является бинарным файлом, который JVM может выполнять. Всё, что нам осталось сделать, — создать такую JVM, которая бы выполняла его корректно.

Если мы заглянем внутрь Add.class с помощью шестнадцатеричного дампа — мы, скорее всего, будем не слишком впечатлены:

Хотя мы еще не видим здесь четкой структуры, нам нужно найти способ ее разобрать: что значит ()V и (II)I, и почему файл начинается с «cafe babe»?

Вероятно, вы знакомы с другим способом выгрузить class файлы, часто он оказывается более полезным:

public static int add(int, int);
Code:
0: iload_0
1: iload_1
2: iadd
3: ireturn
>

Теперь мы видим наш класс, его конструктор и метод. И конструктор, и метод содержат несколько инструкций. Становится более-менее ясно, что делает наш метод add(): он загружает два аргумента (iload_0 и iload_1), суммирует их и возвращает результат. JVM — это стековая машина, поэтому в ней нет регистров, все аргументы инструкций хранятся во внутреннем стеке, и результаты также помещаются в стек.

Class loader

Как нам добиться того же результата, который показала программа javap? Как разобрать class файл?

Если обратиться к спецификации JVM, мы узнаем о структуре файлов формата class. Он всегда начинается с 4-байтовой подписи (CAFEBABE), затем 2 + 2 байта для версии. Звучит просто!

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

Затем спецификация сообщает нам, что необходимо распарсить пул констант. Что это? Так называется специальная часть class файла, которая содержит константы, необходимые для запуска класса. Все строки, числовые константы и ссылки хранятся там, и каждая имеет уникальный индекс uint16 (таким образом, класс может иметь до 64К констант).

В пуле есть несколько типов констант, каждый из которых содержит свой набор значений. Нам могут быть интересны:

Затем, следуя спецификации JVM, мы могли бы извлечь данные пула констант следующим образом:

Сейчас мы сильно упрощаем себе задачу, но в реальной JVM нам пришлось бы обрабатывать типы констант long и double единообразно, вставляя дополнительный неиспользуемый постоянный элемент, как сообщает нам спецификация JVM (поскольку постоянные элементы считаются 32-битными).

Чтобы упростить получение строковых литералов по индексам, реализуем метод Resolve(index uint16) string:

Теперь нам нужно добавить похожие помощники для анализа списка интерфейсов, полей и методов классов и их атрибутов:

И поля, и методы представлены как Fields, это очень удобно, позволяет сэкономить время. Наконец, мы можем собрать всё это вместе и полноценно распарсить наш класс:

Теперь, если мы посмотрим на полученную информацию о классе, мы увидим, что у него нет полей и два метода — :()V и add:(II)I. Что за римские числа со скобками? Это дескрипторы. Они определяют, какие типы аргументов принимает метод и что он возвращает. В этом случае (синтетический метод, используемый для инициализации объектов при их создании) не принимает аргументов и ничего не возвращает (V=void), в то время как метод «add» принимает два типа данных int (I=int32) и возвращает целое число.

Байт-код

Если присмотреться внимательно, мы поймем, что каждый метод в нашем разобранном классе имеет один атрибут с именем «Code». Этот атрибут содержит часть байтов в качестве полезной нагрузки. Байты:

:
[0 1 0 1 0 0 0 5 42 183 0 1 177 0 0 0 1 0 7 0 0 0 6 0 1 0 0 0 1]
add:
[0 2 0 2 0 0 0 4 26 27 96 172 0 0 0 1 0 7 0 0 0 6 0 1 0 0 0 3]

В спецификации, на этот раз в разделе bytecode, мы прочтем, что атрибут «Code» начинается со значения maxstack (2 байта), затем maxlocals (2 байта), длина кода (4 байта) и затем фактический код. Итак, наши атрибуты можно читать так:

: maxstack: 1, maxlocals: 1, code: [42 183 0 1 177]
add: maxstack: 2, maxlocals: 2, code: [26 27 96 172]

Да, у нас есть только 4 и 5 байтов кода в каждом методе. Что означают эти байты?

Как я уже сказал, JVM — это стековая машина. Каждая инструкция кодируется как один байт, за которым могут следовать дополнительные аргументы. Заглянув в спецификацию, мы увидим, что метод «add» имеет следующие инструкции:

26 = iload_0
27 = iload_1
96 = iadd
172 = ireturn

Точно такие же, как мы видели в выводе javap в начале! Но как это сделать?

Фреймы JVM

Когда метод выполняется внутри JVM, у него есть собственный стек для временных операндов, свои локальные переменные и фрагмент кода для выполнения. Все эти параметры хранятся в едином фрейме выполнения. Кроме того, фреймы содержат указатель текущей инструкции (насколько далеко мы продвинулись при выполнении байт-кода) и указатель на класс, в котором содержится метод. Последний нужен для доступа к пулу констант класса, а также к другим деталям.

Давайте создадим метод, который создает фрейм для конкретного метода, вызванного с заданными аргументами. Я буду использовать здесь тип interface<> в качестве типа Value, хотя использование правильного объединения типов (union types), конечно, было бы более безопасным.

Итак, мы получили Frame с инициализированными локальными переменными, пустым стеком и предварительно загруженным байт-кодом. Пришло время выполнить байт-код:

Наконец, мы можем собрать все вместе и запустить, вызвав наш метод add():

Итак, всё работает. Да, это очень слабая JVM на минималках, но все же она делает то, что и должна JVM: загружает байт-код и интерпретирует его (конечно, настоящая JVM делает гораздо большее).

Чего не хватает?

Оставшихся 200 инструкций, среды выполнения, системы типов ООП и еще нескольких вещей.

Существует 11 групп инструкций, большинство из которых банальны:

Для реализации References необходимо подумать об объектной модели: как вы хотите хранить объекты и их классы, как представлять наследование, где хранить поля экземпляров и поля классов. Кроме того, здесь вы должны быть осторожны с диспетчеризацией методов — существует несколько инструкций «invoke», и они ведут себя по-разному:

Наконец, ваша JVM останется бесполезной, если нет runtime классов. Без java/lang/Object вы вряд ли даже увидите, как работает new инструкция при создании новых объектов. Ваша среда выполнения может предоставлять некоторые общие классы JRE из пакетов java.lang, java.io и java.util, или это может быть что-то более специфичное для домена. Скорее всего, некоторые методы в классах должны быть реализованы изначально, а не на Java. Это поднимет вопрос о том, как найти и выполнить такие методы, и станет еще одним крайним случаем для вашей JVM.

Другими словами, создать правильную JVM не так уж и просто, однако разобраться, как именно она работает, — не сложно.

У меня, например, на это ушли всего одни летние выходные. Моей JVM еще предстоит долгий путь, но структура выглядит более или менее ясной: https://github.com/zserge/tojvm (замечания всегда приветствуются!)

Фактические фрагменты кода из этой статьи еще меньше и доступны здесь как gist.

Если появилось желание изучить вопрос лучше, вы можете подумать об использовании небольших JVM:

Надеюсь, вам понравилась моя статья. Вы можете следить за моей работой через Github или Twitter, а также подписываться через rss.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *