150 lines
18 KiB
Markdown
150 lines
18 KiB
Markdown
###### JVM (Java Virtual Machine)
|
||
|
||
Виртуальная машина Java (JVM) - это механизм, обеспечивающий среду выполнения для управления Java-кодом или приложениями.
|
||
Виртуальная машина является независимой оболочкой исполнения кода, благодаря которой возможен запуск на любой ОС,
|
||
без влияния ОС на выполняемую программу.
|
||
|
||
За что отвечает JVM:
|
||
1. Загрузка, проверка (верификация) и исполнение байт кода;
|
||
2. Предоставление среды выполнения для выполнения байт-кода;
|
||
3. Управление памятью и очисткой мусора (Garbage collection);
|
||
|
||
JVM работает с 2мя типами данных: примитивные типы (**primitive types**) и ссылочные типы (**reference types**).
|
||
|
||
**Примитивы**
|
||
|
||
JVM работает с примитивными значениями (целыми числами и числами с плавающей точкой) и ссылками. По сути, JVM - это 32-битная машина.
|
||
Типы `long` и `double`, которые являются 64-битными, поддерживаются изначально,
|
||
но занимают две единицы памяти в `frame's local` или стеке операндов, поскольку каждая единица составляет 32 бита.
|
||
Типы `boolean`, `byte`, `short` и `char` имеют расширенный знак (кроме `char` с нулевым расширением) и работают как 32-разрядные целые числа, так же как и типы `int`.
|
||
Меньшие типы имеют только несколько специфических для типа инструкций для загрузки, хранения и преобразования типов.
|
||
`boolean` значение работает как 8-битное `byte` значения, где 0 представляет значение **false**, а 1 - значение **true**.
|
||
В JVM есть сборщик мусора (garbage-collector) для хранения объектов и массивов. Код, константы и другие данные класса хранятся в «области метода».
|
||
Область метода является логически частью кучи, но реализации могут обрабатывать область метода отдельно от кучи и, например, могут не собирать мусор.
|
||
Каждый поток JVM также имеет свой собственный стек вызовов (для ясности называемый «стек виртуальных машин Java»), в котором хранятся `frames`.
|
||
Новый фрейм (`frame`) создается каждый раз, когда вызывается метод, и фрейм уничтожается при выходе из этого метода.
|
||
|
||
**Типы ссылок и значения**
|
||
|
||
Существует три типа ссылочных типов: типы классов, типы массивов и типы интерфейсов.
|
||
Их значения являются ссылками на динамически создаваемые экземпляры классов, массивы или экземпляры классов или массивы,
|
||
которые реализуют интерфейсы соответственно.
|
||
|
||
|
||
![JVM Architecture]
|
||
(jvmarchitecture.png)
|
||
|
||
###### 1. Classloader (Загрузчик классов)
|
||
|
||
Java Classloader является частью JRE, которая динамичиски закгружает Java классы в JVM.
|
||
Обычно классы загружаются только по запросу. Система исполнения в Java не должна знать о файлах и файловых системах
|
||
благодаря загрузчику классов. Делегирование является важной концепцией, которую выполняет загрузчик. Загрузчик классов
|
||
отвечает за поиск библиотек, чтение их содержимого и загрузку классов, содержащихся в библиотеках.
|
||
Эта загрузка обычно выполняется «по требованию», поскольку она не происходит до тех пор, пока программа не вызовет класс.
|
||
Класс с именем может быть загружен только один раз данным загрузчиком классов.
|
||
|
||
При запуске JVM, используются три загрузчика классов:
|
||
* Bootstrap class loader (Загрузчик класса Bootstrap)
|
||
* Extensions class loader (Загрузчик класса расширений)
|
||
* System class loader (Системный загрузчик классов)
|
||
|
||
**Загрузчик класса Bootstrap** загружает основные библиотеки Java, расположенные в папке `<JAVA_HOME>/jre/lib`.
|
||
Этот загрузчик является частью ядра JVM, написан на нативном коде.
|
||
|
||
**Загрузчик класса расширений** загружает код в каталоги расширений
|
||
(`<JAVA_HOME>/jre/lib/ext`, или любой другой каталог, указанный системным свойством `java.ext.dirs`).
|
||
|
||
**Системный загрузчик** загружает код, найденный в `java.class.path`, который сопоставляется с переменной среды `CLASSPATH`.
|
||
Это реализуется классом `sun.misc.Launcher$AppClassLoader`.
|
||
|
||
**Пользовательский загрузчик классов**
|
||
|
||
Загрузчик классов написан на Java. Поэтому возможно создать свой собственный загрузчик классов, не понимая тонких деталей JVM.
|
||
У каждого загрузчика классов Java есть родительский загрузчик классов, определенный при создании экземпляра нового
|
||
загрузчика классов или в качестве системного загрузчика классов по умолчанию для виртуальной машины.
|
||
|
||
Что делает возможным следующее:
|
||
* загружать или выгружать классы во время выполнения (например, динамически загружать библиотеки во время выполнения, даже из ресурса HTTP).
|
||
Это важная особенность для:
|
||
- реализация скриптовых языков;
|
||
- использование bean builders;
|
||
- добавить пользовательскую расширение;
|
||
- позволяя нескольким пространствам имен общаться. Например, это одна из основ протоколов CORBA / RMI;
|
||
* изменить способ загрузки байт-кода (например, можно использовать зашифрованный байт-код класса Java);
|
||
* модифицировать загруженный байт-код (например, для переплетения аспектов во время загрузки при использовании аспектно-ориентированного программирования);
|
||
|
||
Загрузчик классов выполняет три основных действия в этом строгом порядке:
|
||
* Загрузка: находит и импортирует двоичные данные для типа.
|
||
* Связывание: выполняет проверку, подготовку и (необязательно) разрешение.
|
||
- Проверка: обеспечивает правильность импортируемого типа.
|
||
- Подготовка: выделяет память для переменных класса и инициализация памяти значениями по умолчанию.
|
||
- Разрешение: преобразует символические ссылки из типа в прямые ссылки.
|
||
* Инициализация: вызывает код Java, который инициализирует переменные класса их правильными начальными значениями.
|
||
|
||
###### 2. Области данных времени выполнения (Run-Time Data Areas)
|
||
|
||
JVM выделяет множество областей данных во время выполнения, к-рые используются во время выполнения программы. Некоторые участки данных
|
||
созданы JVM во время старта и уничтожаются во время её выключения. Другие создаются для каждого потока и уничтожаются когда поток уничтожается.
|
||
|
||
2.1. The pc Register
|
||
|
||
Виртуальная машина Java может поддерживать много потоков исполнения одновременно. Каждый поток виртуальной машины Java имеет свой собственный регистр PC (programm counter).
|
||
В любой момент каждый поток виртуальной машины Java выполняет код одного метода, а именно текущий метод для этого потока.
|
||
Если этот метод не является native, регистр pc содержит адрес инструкции виртуальной машины Java, выполняемой в настоящее время.
|
||
|
||
2.2. Java Virtual Machine Stacks
|
||
|
||
Каждый поток виртуальной машины Java имеет собственный стек виртуальной машины Java, созданный одновременно с потоком.
|
||
Стек виртуальной машины Java хранит frames. Cтеки виртуальных машин Java могут иметь фиксированный размер
|
||
или динамически расширяться и сжиматься в соответствии с требованиями вычислений.
|
||
|
||
2.3. Heap
|
||
|
||
Виртуальная машина Java имеет кучу, которая используется всеми потоками виртуальной машины Java.
|
||
Куча - это область данных времени выполнения, из которой выделяется память для всех экземпляров и массивов классов.
|
||
Куча создается при запуске виртуальной машины. Хранилище для объектов восстанавливается автоматической системой
|
||
управления данными (известной как сборщик мусора); объекты никогда не освобождаются явно.
|
||
Виртуальная машина Java не предполагает какого-либо конкретного типа системы автоматического управления хранением данных,
|
||
и метод управления может быть выбран в соответствии с системными требованиями разработчика.
|
||
Куча может иметь фиксированный размер или может быть расширена в соответствии с требованиями вычислений и может быть сокращена,
|
||
если большая куча становится ненужной. Память для кучи не должна быть смежной.
|
||
|
||
2.4. Method Area
|
||
|
||
Виртуальная машина Java имеет область методов, которая является общей для всех потоков виртуальной машины Java.
|
||
Область метода аналогична области хранения скомпилированного кода на традиционном языке или аналогична сегменту «текст» в процессе операционной системы.
|
||
Он хранит структуры для каждого класса, такие как пул постоянных времени выполнения, данные полей и методов,
|
||
а также код для методов и конструкторов, включая специальные методы, используемые при инициализации классов и экземпляров и инициализации интерфейса.
|
||
|
||
Хотя область метода является логически частью кучи, простые реализации могут не обрабатываться собиращиком мусора. Область метода может иметь
|
||
фиксированный размер или может быть расширена в соответствии с требованиями вычислений и может быть сокращена, если большая область метода становится ненужной.
|
||
|
||
2.5. Run-Time Constant Pool
|
||
|
||
A run-time constant pool существует для каждого класса или интерфейса в рантайме и представленно constant_pool таблицей в *.class файле.
|
||
Он содержит несколько видов констант: от числовых литералов, известных во время компиляции, до ссылок на методы и поля,
|
||
которые должны быть разрешены во время выполнения. Сам run-time constant pool выполняет функцию,
|
||
аналогичную функции таблицы символов для обычного языка программирования, хотя он содержит более широкий диапазон данных, чем типичная таблица символов.
|
||
Каждый run-time constant pool отделён от JVM's method area. JVM создаёт run-time constant pool вместе с созданием class или interface.
|
||
|
||
2.6. Native Method Stacks
|
||
|
||
Реализация виртуальной машины Java может использовать обычные стеки, обычно называемые «стеки С», для поддержки native methods (методов, написанных на языке, отличном от языка программирования Java).
|
||
|
||
|
||
###### 3. Frames
|
||
|
||
Frame используется для хранения данных и частичных результатов, а также для выполнения динамического связывания, возврата значений для методов и отправки исключений.
|
||
Новый frame создается каждый раз, когда вызывается метод. Frame уничтожается, когда завершается его вызов метода,
|
||
является ли это завершение нормальным или резким (он генерирует неперехваченное исключение). Frames выделяются из стека потока, создающего frame.
|
||
Каждый frame имеет свой собственный массив локальных переменных, свой собственный стек операндов и ссылку на пул констант во время выполнения класса текущего метода.
|
||
Размеры массива локальных переменных и стека операндов определяются во время компиляции и предоставляются вместе с кодом для метода, связанного с фреймом.
|
||
Таким образом, размер структуры данных frame-а зависит только от реализации виртуальной машины Java, и память для этих структур может быть выделена одновременно при вызове метода.
|
||
|
||
Только один frame, frame для метода выполнения, активен в любой точке данного потока управления. Этот кадр называется текущим frame, а его метод известен как текущий метод.
|
||
Класс, в котором определен текущий метод, является текущим классом. Операции над локальными переменными и стеком операндов обычно выполняются со ссылкой на текущий frame.
|
||
|
||
Frame перестает быть текущим, если его метод вызывает другой метод или если его метод завершается. Когда метод вызывается, новый frame создается и становится текущим,
|
||
когда управление переходит к новому методу. При возврате метода текущий frame передает результат вызова метода, если таковой имеется, в предыдущий frame.
|
||
Текущий frame затем отбрасывается, так как предыдущий frame становится текущим. Обратите внимание, что frame, созданный потоком, является локальным для этого потока и на него не может ссылаться ни один другой поток.
|