Что такое jvm java

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

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

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm 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).

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm 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).

Источник

Архитектура JVM: обзор архитектуры JVM и JVM

Привет читатели! В этом руководстве мы поймем и изучим виртуальную машину Java (JVM) и ее архитектуру. Этот урок поможет вам правильно ответить на следующие вопросы:

1. Введение

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

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm java

Рис. 1: Обзор виртуальной машины Java

1.1 Что делает JVM?

Виртуальная машина Java выполняет следующие операции:

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm java

Рис. 2: компоненты JVM

1.2 Типы виртуальных машин Java

Редакция Java имеет две разные реализации виртуальной машины Java (JVM), т.е.

1.3 Внутренняя архитектура JVM

На схеме показаны ключевые внутренние компоненты виртуальной машины Java, соответствующие спецификации JVM.

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm java

Рис. 3: Архитектура виртуальной машины Java

Компоненты, показанные на рис. 3, поясняются ниже.

1.3.1 Класс Loader

1.3.2 Области данных времени выполнения

Эта подсистема разделена на пять основных компонентов, т.е.

Эта область играет важную роль во время вызова метода и возврата.

1.3.3 Механизм исполнения

Этот компонент выполняет байт-код, который назначается областям данных времени выполнения и имеет три основных подкомпонента, а именно:

Источник

Как работает виртуальная машина Java — взгляд изнутри

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm java

Рассказывает Роман Иванов

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

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

Рассмотрим схему работы JVM более подробно.

Структура class-файла

Напишем простейшее приложение и скомпилируем его. Компилятор заботливо создаст файл с расширением class и поместит туда всю информацию о нашем мини-приложении для JVM. Что мы увидим внутри? Файл поделён на десять секций, последовательность которых строго задана и определяет всю структуру class-файла.

Файл начинается со стартового (магического) числа: 0xCAFEBABE. Данное число присутствует в каждом классе и является обязательным флагом для JVM: с его помощью система понимает, что перед ней class-файл.

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm java

С девятого байта идёт пул констант, в котором содержатся все константы нашего класса. Так как в каждом классе их может быть различное количество, то перед массивом находится переменная, указывающая на его длину, то есть пул констант представляет из себя массив переменной длины. Каждая константа занимает один элемент в массиве. Во всём class-файле константы указываются целочисленным индексом, который обозначает их положение в массиве. Начальная константа имеет индекс 1, вторая константа — 2 и т. д.

Каждый элемент пула констант начинается с однобайтового тега, определяющего его тип. Это позволяет JVM понять, как правильно обработать идущую далее константу. Всего зарезервировано 14 типов констант:

Тип константыЗначение тега
CONSTANT_Class7
CONSTANT_Fieldref9
CONSTANT_Methodref10
CONSTANT_InterfaceMethodref11
CONSTANT_String8
CONSTANT_Integer3
CONSTANT_Float4
CONSTANT_Long5
CONSTANT_Double6
CONSTANT_NameAndType12
CONSTANT_Utf81
CONSTANT_MethodHandle15
CONSTANT_MethodType16
CONSTANT_InvokeDynamic18

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

Прочитав блок с константами, JVM переходит к следующим двум байтам — флагам доступа, которые определяют, описывает этот файл класс или интерфейс, общедоступный или абстрактный, является ли класс финальным.

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

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

Имя флагаКодОпределение
ACC_PUBLIC0x0001Объявлен публичным
ACC_FINAL0x0010Объявлен финальным
ACC_SUPER0x0020Специальный флаг, введённый в версии Java 1.1 для совместимости при вызове методов родителя
ACC_INTERFACE0x0200Объявлен интерфейсом
ACC_ABSTRACT0x0400Объявлен абстрактным
ACC_SYNTHETIC0x1000Зарезервированное определение
ACC_ANNOTATION0x2000Объявлен аннотацией
ACC_ENUM0x4000Объявлен перечислением

Подобную структуру имеет и следующий блок — Fields.

Этот блок начинается с двухбайтового параметра количества полей в этом классе или интерфейсе. За ним идёт массив структур переменной длины. Каждая структура содержит информацию об одном поле: имя поля, тип, значение, если это, например, финальная переменная. В списке отображаются только те поля, которые были объявлены классом или интерфейсом, определённым в файле. Поля от родительских классов и имплементированных интерфейсов здесь не присутствуют, они задаются в своих class-файлах.

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

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

В последнем блоке идёт дополнительная мета-информация, например имя файла, который был скомпилирован. Она может присутствовать, а может и нет. В случае каких-то проблем JVM просто игнорирует этот блок.

Загрузка классов

Теперь, разобравшись с общей структурой файла, посмотрим, как JVM его обрабатывает.

Чтобы попасть в JVM, класс должен быть загружен. Для этого существуют специальные классы-загрузчики:

Главный класс приложения всегда загружается системным загрузчиком, остальные же классы могут быть загружены различными пользовательскими загрузчиками. Стоит упомянуть, что имя загрузчика создаёт уникальное пространство имён, то есть в программе может существовать несколько классов с одним и тем же полным именем, если они обрабатывались разными загрузчиками.
Поэтому каждый загрузчик делегирует свои полномочия родителю, то есть перед поиском класса для загрузки он попытается узнать, не был ли загружен нужный класс раньше.

После загрузки класса начинается этап линковки, который делится на три части.

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

JVM получает один поток байтовых кодов для каждого метода в классе. Байт-код метода выполняется, когда этот метод вызывается в ходе работы программы. Поток байт-кода метода — это последовательность инструкций для виртуальной машины Java. Каждая инструкция состоит из однобайтового кода операции, за которым может следовать несколько операндов. Код операции указывает действие, которое нужно предпринять. Всего на данный момент в Java более 200 операций. Все коды операций занимают только 1 байт, так как они были разработаны компактными, поэтому их максимальное число не может превысить 256 штук.

В основе работы JVM находится стек — основные инструкции работают с ним.

Рассмотрим пример умножения двух чисел. Ниже представлен байт-код метода:

На Java это будет выглядеть так:

По листингу выше можно заметить, что коды операций сами по себе указывают тип и значение. Например, код операции iconst_1 указывает JVM на целочисленное значение, равное единице. Такие байт-коды определены для самых часто используемых констант. Эти инструкции занимают 1 байт и введены специально для повышения эффективности выполнения байт-кода и уменьшения размера его потока. Подобные короткие константы также присутствуют и для других типов данных.

Всего JVM поддерживает семь примитивных типов данных: byte, short, int, long, float, double и char.

Если бы мы хотели положить в переменную а другое значение, например 11112, то нам пришлось бы использовать инструкцию sipush :

Данные операции выполняются в так называемом фрейме стека метода. У каждого метода есть некоторая своя часть в общем стеке. Таким образом в нашем главном потоке исполнения программы создаются множество подстеков на каждый вызов метода. Более наглядно это представлено на картинке ниже:

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm java

В каждом стек-фрейме хранится массив локальных переменных, который позволяет сохранять и доставать локальные переменные, как мы сделали в примере выше, поместив значения 1 и 5 в переменные 1 и 2. Стоить отметить, что здесь компилятор также оптимизировал байт-код, используя однобайтовые инструкции. Если бы переменных в нашем методе было много, использовался бы код операции сохранения значения вместе с указанием позиции переменной в массиве.

Вызовы методов

Java предоставляет два основных вида методов: методы экземпляра и методы класса. Методы экземпляра используют динамическое (позднее) связывание, тогда как методы класса используют статическое (раннее) связывание.

Возвращаемое методом значение кладётся на стек. Типы возвращаемых значений методов указаны ниже:

ОперацияОписание
ireturnПомещает на стек значение типа int
lreturnПомещает на стек значение long,
freturnПомещает на стек значение float
dreturnПомещает на стек значение double
areturnПомещает на стек значение object
returnНе изменяет стек

Циклы

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

Заключение

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

Таким образом, мы поверхностно рассмотрели жизненный цикл байткода в JVM: class-файлы, их загрузку и выполнение байт-кода и базовые инструкции.

Источник

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

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

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

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

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm 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. Это значит, что загрузка классов не будет выполняться до тех пор, пока в приложении не встретится обращение к классу.

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

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm 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” или “Последним вошел, первым вышел”.

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm java

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

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

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

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

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm java

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

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

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

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

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

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

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm 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().

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm 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.

Что такое jvm java. Смотреть фото Что такое jvm java. Смотреть картинку Что такое jvm java. Картинка про Что такое jvm java. Фото Что такое jvm java

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

Источник

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

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