что такое byte code java

Java Bytecode Fundamentals

Разработчики приложений на Java обычно не нуждаются в знании о байт-коде, выполняющемся в виртуальной машине, однако тем, кто занимается разработкой современных фреймворков, компиляторов или даже инструментов Java может понадобиться понимание байт-кода и, возможно, даже понимание того, как его использовать в своих целях. Несмотря на то, что специальные библиотеки типа ASM, cglib, Javassist помогают в использовании байт-кода, необходимо понимание основ для того, чтобы использовать эти библиотеки эффективно.
В статье описаны самые основы, от которых можно отталкиваться в дальнейшем раскапывании данной темы (прим. пер.).

Давайте начнём с простого примера, а именно POJO с одним полем и геттером и сеттером для него.

Когда вы скомпилируете класс, используя команду javac Foo.java, у вас появится файл Foo.class, содержащий байт-код. Вот как его содержание выглядит в HEX-редакторе:

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

Каждая пара шестнадцатеричных чисел (байт) переводится в опкоды (мнемоника). Было бы жестоко попытаться прочитать это в двоичном формате. Давайте перейдем к мнемоничному представлению.

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

Далее, изучая байт-кодовые инструкции (у нас это aload_0 и aload_1), мы видим, что некоторые из них имеют префиксы типа aload_0 и istore_2. Это относится к типу данных, с которыми оперирует инструкция. Префикс «a» обозначает, что опкод управляет ссылкой на объект. «i», соответственно, управляет integer.

Теперь видно, что это за странные операнды. Например, #2:

const #2 = Field #3.#18; // Foo.bar:Ljava/lang/String;

const #3 = class #19; // Foo
const #18 = NameAndType #5:#6;// bar:Ljava/lang/String;

Отметим, что, каждый код операции помечен номером (0: aload_0). Это указание на позицию инструкции внутри фрейма — дальше объясню, что это значит.

Чтобы понять, как работает байт-код, достаточно взглянуть на модель выполнения. JVM использует модель выполнения на основе стеков. Каждый тред имеет JVM-стек, содержащий фреймы. Например, если мы запустим приложение в дебаггере, то увидим следующие фреймы:
что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

При каждом вызове метода создается новый фрейм. Фрейм состоит из стека операнда, массива локальных переменных и ссылку на пул констант класса выполняемого метода.
что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

Размер массива локальных переменных определяется во время компиляции в зависимости от количества и размера локальных переменных и параметров метода. Стек операндов — LIFO-стек для записи и удаления значений в стеке; размер также определяется во время компиляции. Некоторые опкоды добавляют значения в стек, другие берут из стека операнды, изменяют их состояние и возвращают в стек. Стек операндов также используется для получения значений, возвращаемых методом (return values).

Байткод для этого метода состоит из трёх опкодов. Первый опкод, aload_0, проталкивает в стек значение с индексом 0 из таблицы локальных переменных. Ссылка this в таблице локальных переменных для конструкторов и instance-методов всегда имеет индекс 0. Следующий опкод, getfield, достает поле объекта. Последняя инструкция, areturn, возвращает ссылку из метода.

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

Так, байткод для метода getBar — 2A B4 00 02 B0. 2A относится к инструкции aload_0, B0 — к areturn. Может показаться странным, что байткод для метода имеет три инструкции, а в массиве байт 5 элементов. Это связано с тем, что getfield (B4) нуждается в двух параметрах (00 02), занимающих позиции 2 и 3 в массиве, отсюда и 5 элементов в массиве. Инструкция areturn сдвигается на 4 позицию.
Таблица локальных переменных

Для иллюстрации того, что происходит с локальными переменными, воспользуемся ещё одним примером:

Здесь две локальных переменных — параметр метода и локальная переменная int b. Вот как выглядит байт-код:

LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this LExample;
0 6 1 a I
2 4 2 b I

Метод загружает константу 1 с помощью iconst_1 и ложит её в локальную переменную 2 с помощью istore_2. Теперь в таблице локальных переменных слот 2 занят переменной b, как и ожидалось. Далее, iload_1 загружает значение в стек, iload_2 загружает значение b. iadd выталкивает 2 операнда из стека, добавляет их и возвращает значение метода.
Обработка исключений

Интересный пример того, какой получается байт-код в случае с обработкой исключений, например, для конструкции try-catch-finally.

Байт-код для метода foo():

Компилятор генерирует код для всех сценариев, возможных внутри блока try-catch-finally: finallyMethod() вызывается три раза(!). Блок try скомпилировался так, как будто try не было и он был объединён с finally:
0: aload_0
1: invokespecial #2; //Method tryMethod:()V
4: aload_0
5: invokespecial #3; //Method finallyMethod:()V
Если блок выполняется, то инструкция goto перекидывает выполнение на 30-ю позицию с опкодом return.

Если tryMethod бросит Exception, будет выбран первый подходящий (внутренний) обработчик исключений из таблицы исключений. Из таблицы исключений мы видим, что позиция с перехватом исключения равна 11:

0 4 11 Class java/lang/Exception

Это перекидывает выполнение на catchMethod() и finallyMethod():

11: astore_1
12: aload_0
13: invokespecial #5; //метод catchMethod:()V
16: aload_0
17: invokespecial #3; //метод finallyMethod:()V

Если в процессе выполнения будет брошено другое исключение, мы увидим, что в таблице исключений позиция будет равна 23:

0 4 23 any
11 16 23 any
23 24 23 any

Инструкции, начиная с 23:

23: astore_2
24: aload_0
25: invokespecial #3; //Method finallyMethod:()V
28: aload_2
29: athrow
30: return

Так что finallyMethod() будет выполнен в любом случае, с aload_2 и athrow, бросающим необрабатываемое исключение.

Это всего лишь несколько моментов из области байткода JVM. Большинство было почерпнуто из статьи developerWorks Peter Haggar — Java bytecode: Understanding bytecode makes you a better programmer. Статья немного устарела, но до сих пор актуальна. Руководство пользователя BCEL содержит достойное описание основ байт-кода, поэтому я предложил бы почитать его интересующимся. Кроме того, спецификация виртуальной машины также может быть полезным источником информации, но ее нелегко читать, кроме этого отсутствует графический материал, который бывает полезным при понимании.

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

Источник

Введение в байт-код Java

что такое byte code java. 0*rMLC4Ew14zneFpfQ. что такое byte code java фото. что такое byte code java-0*rMLC4Ew14zneFpfQ. картинка что такое byte code java. картинка 0*rMLC4Ew14zneFpfQ.

May 15 · 6 min read

что такое byte code java. 1*zGB84bWzuyTJ mLArMBtKA. что такое byte code java фото. что такое byte code java-1*zGB84bWzuyTJ mLArMBtKA. картинка что такое byte code java. картинка 1*zGB84bWzuyTJ mLArMBtKA.

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

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

Что такое байт-код Java?

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

Как генерируется байт-код?

Как посмотреть байт-код Java?

Если вам хочется увидеть сам байт-код, простейший способ — воспользоваться командной строкой.

Как работает JVM

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

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

Фрейм состоит из локальной среды, которая необходима для поддержания его выполнения. Как правило он содержит массив локальных переменных и стек операндов. Посмотрим, что эти элементы из себя представляют.

Массив локальных переменных

Массив локальных переменных, как следует из названия, нужен для хранения локальных переменных в методе. Также он хранит аргументы, которые принимает метод.

Определим два метода: один статический и один метод экземпляра, но схожие во всем остальном.

Локальные массивы переменных для этих методов будут выглядеть следующим образом:

что такое byte code java. . что такое byte code java фото. что такое byte code java-. картинка что такое byte code java. картинка .

Стек операндов

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

Инструкция байт-кода load и ее расширения нужны для перемещения значения, хранящегося в массиве переменных, в стек. Инструкция store применяется для извлечения значений из стека и сохранения в массиве переменных. Существуют и другие инструкции, которые извлекают значения из стека для обработки.

что такое byte code java. 1*MJ6mqP490nKErFoZoNcWEA. что такое byte code java фото. что такое byte code java-1*MJ6mqP490nKErFoZoNcWEA. картинка что такое byte code java. картинка 1*MJ6mqP490nKErFoZoNcWEA.

Посмотрим в байт-код

Ради возможности вглядеться в байт-код, я написал простой Java-класс:

Деконструкция байт-кода

Здесь важно отметить еще одно: индексы, заданные инструкциям байт-кода — как видим, они не увеличиваются на единицу для каждой новой инструкции.

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

Вывод

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

Источник

Байт-код Java: чудеса или реальность?

что такое byte code java. bate code Java. что такое byte code java фото. что такое byte code java-bate code Java. картинка что такое byte code java. картинка bate code Java.Основная особенность Java, которая позволяет решать описанные ранее про­блемы обеспечения безопасности и переносимости программ, состоит в том, что компилятор Java выдает не исполняемый код, а так называемый байт-код в выс­шей степени оптимизированный набор инструкций, предназначенных для выполнения в исполняющей системе Java, называемой виртуальной машиной Java (Java Virtual Machine — JVM). Собственно говоря, первоначальная версия виртуальной машины JVM разрабатывалась в качестве интерпретатора байт-кода. Это может вызывать недоумение, поскольку для обеспечения максимальной производитель­ности компиляторы многих современных языков программирования призваны создавать исполняемый код. Но то, что программа на Java интерпретируется вир­туальной машиной JVM, как раз помогает решить основные проблемы разработки программ для Интернета. И вот почему.

Трансляция программы Java в байт-код значительно упрощает ее выполнение в разнотипных средах, поскольку на каждой платформе необходимо реализовать только виртуальную машину JVM. Если в отдельной системе имеется исполняю­щий пакет, в ней можно выполнять любую программу на Java. Следует, однако, иметь в виду, что все виртуальные машины JVM на разных платформах, несмотря на некоторые отличия и особенности их реализации, способны правильно ин­терпретировать один и тот же байт-код. Если бы программа на Java компилирова­лась в машинозависимый код, то для каждого типа процессоров, подключенных к Интернету, должны были бы существовать отдельные версии одной и той же программы. Ясно, что такое решение неприемлемо. Таким образом, организация выполнения байт-кода виртуальной машиной JVM — простейший способ создания по-настоящему переносимых программ.

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

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

Язык Java был задуман как интерпретируемый, но ничто не препятствует ему оперативно выполнять компиляцию байт-кода в машинозависимый код для повы­шения производительности. Поэтому вскоре после выпуска Java появилась техно­логия HotSpot, которая предоставляет динамический компилятор (или так называ­емый JIT-компилятор) байт-кода. Если динамический компилятор входит в состав виртуальной машины JVM, то избранные фрагменты байт-кода компилируются в исполняемый код по частям, в реальном времени и по требованию. Важно по­нимать, что одновременная компиляция всей программы Java в исполняемый код нецелесообразна, пocкoлькyJava производит различные проверки, которые могут быть сделаны только во время выполнения. Вместо этого динамический компи­лятор компилирует код во время выполнения по мере надобности. Более того, компилируются не все фрагменты байт-кода, а только те, которым компиляция принесет выгоду, а остальной код просто интерпретируется. Тем не менее прин­цип динамической компиляции обеспечивает значительное повышение произ­водительности. Даже при динамической компиляции байт-кода характеристики переносимости и безопасности сохраняются, поскольку виртуальная машина JVM по-прежнему отвечает за целостность исполняющей среды.

Источник

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

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

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

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

что такое byte code java. e7qk0ed8rejsgfy30aaosw8yrya. что такое byte code java фото. что такое byte code java-e7qk0ed8rejsgfy30aaosw8yrya. картинка что такое byte code java. картинка e7qk0ed8rejsgfy30aaosw8yrya.

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

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

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

Write Once Run Anywhere (WORA)

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

Write Once Compile Anywhere (WOCA)

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

Байткод

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

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

Кухня JVM

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

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

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

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

что такое byte code java. ism v2gh1keewv8lsjhoni3g vg. что такое byte code java фото. что такое byte code java-ism v2gh1keewv8lsjhoni3g vg. картинка что такое byte code java. картинка ism v2gh1keewv8lsjhoni3g vg.

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

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

что такое byte code java. . что такое byte code java фото. что такое byte code java-. картинка что такое byte code java. картинка .

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

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

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

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

JVM Stack

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

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

что такое byte code java. ti3kfyzgveqkh726jelzbedkpvk. что такое byte code java фото. что такое byte code java-ti3kfyzgveqkh726jelzbedkpvk. картинка что такое byte code java. картинка ti3kfyzgveqkh726jelzbedkpvk.

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

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

что такое byte code java. tlasrl j3ocbkzd irebk0usgsu. что такое byte code java фото. что такое byte code java-tlasrl j3ocbkzd irebk0usgsu. картинка что такое byte code java. картинка tlasrl j3ocbkzd irebk0usgsu.

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

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

что такое byte code java. ic90m1h3sbynrbt. что такое byte code java фото. что такое byte code java-ic90m1h3sbynrbt. картинка что такое byte code java. картинка ic90m1h3sbynrbt.

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

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

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

что такое byte code java. . что такое byte code java фото. что такое byte code java-. картинка что такое byte code java. картинка .

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

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

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

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

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

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

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

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

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

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

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

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

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

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

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

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

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

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

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

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

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

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

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

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

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

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

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

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

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

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

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

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

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

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

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

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

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

что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

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

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

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

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

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

Источник

Основы Java Bytecode

Что будет и кому может быть интересно

Внимание, статья содержит довольно много картинок и получилась довольно тяжелой и объемной

В данной статье будут рассмотрены только основы Java Bytecode. Если вы уже знакомы с его основами, статья вряд ли будет вам интересна, так как практически все можно найти в документации.

В данной статье не рассмотрены многие темы (например, фреймы, многие атрибуты), иначе она бы получилась еще больше

Зачем знать что-то о Bytecode

Тема bytecode довольно скучная и в реальной работе среднестатистического программиста практически не используется.

Так почему стоит знать про основы bytecode:

что такое byte code java. bc8d5754a255d2aac8567cf9c0e6f4b9. что такое byte code java фото. что такое byte code java-bc8d5754a255d2aac8567cf9c0e6f4b9. картинка что такое byte code java. картинка bc8d5754a255d2aac8567cf9c0e6f4b9.

    Потому что с этим работает Java Machine и хочется понимать, что лежит в основе

    Потому что многие современные фреймворки что-то тихо делают на уровне bytecode и часто могут что-то там сломать (привет, Lombok)

    Потому что просто стало скучно 🙂

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

    javap может принимать много параметров. Давайте рассмотрим основные из них.

    Смотреть будем на стандартном классе java.lang.Object

    Без параметров

    Выводится только основная информация по классам, методам и полям (приватные поля и методы не показываются)

    Показываются также приватные поля и методы

    Показываются подробную информацию (verbose), такую, как размер стека и аргументов, версии и т.д.

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

    что такое byte code java. 3c361cf7673358cfcc15311ee14fe7c9. что такое byte code java фото. что такое byte code java-3c361cf7673358cfcc15311ee14fe7c9. картинка что такое byte code java. картинка 3c361cf7673358cfcc15311ee14fe7c9.Просмотр для Java что такое byte code java. 0f00e91c306349fd4b012e43b3d4fc0f. что такое byte code java фото. что такое byte code java-0f00e91c306349fd4b012e43b3d4fc0f. картинка что такое byte code java. картинка 0f00e91c306349fd4b012e43b3d4fc0f.Просмотр для Kotlin

    Версии class файлов

    Чтобы понять, какие версии class файлов какая jvm поддерживает, можно воспользоваться таблицей из документации:

    Поддерживаемые major версии

    Для версии Java, начиная с 5, работает формула Major-44=Версия Java

    access_flags

    Flag Name (Имя флага)

    public, виден за пределами пакета

    final ; не может быть наследован

    Обработка методов супер-класса когда вызывается инструкция invokespecial. (ссылка на более подробное объяснение)

    Интерфейс, не класс

    Абстрактный, не может быть наследован

    Синтетический, не из кода

    Модуль, не класс или интерфейс

    Внутрь Bytecode

    Рассмотрим первый простой файл:

    Версия 55.0, что соответствует версии Java 11 (55-44=11)

    Рассмотрим теперь файл с каким-нибудь полем :

    Часть bytecode, касающаяся поля:

    Для полей приведены флаги доступа, имя, описание (сигнатура поля) и атрибуты (здесь, ConstantValue)

    Сигнатуры (descriptor) для полей имеют следующий формат:

    Описание структуры метода

    Рассмотрим простой класс:

    Документацию можно посмотреть тут.

    Выполнение метода

    Основы

    Продолжим работать с предыдущим примером.

    Инструкции JVM занимают 1 байт, затем следуют параметры инструкции (если они есть).

    что такое byte code java. 082885a9ca51f1bc14ceba3ac1acf0d7. что такое byte code java фото. что такое byte code java-082885a9ca51f1bc14ceba3ac1acf0d7. картинка что такое byte code java. картинка 082885a9ca51f1bc14ceba3ac1acf0d7.

    iconst_1. Кладет на стек 1.

    istore_1. Снимает значение с вершины стека и записывает в локальную переменную под индексом 1

    iload_1. Записывает на вершину стека значение из переменной под индексом 1.

    iconst_2. Записывает на вершину стека значение 2.

    iadd. Снимает с вершины стека два целых числа, суммирует их и кладет полученный результат на вершину стека

    istore_2. Снимает значение с вершины стека и записывает в локальную переменную под индексом 2

    getstatic #2. Находит ссылку на статическое поле указанное в пуле под индексом #2 и кладет ее на вершину стека

    iload_2. Записывает на вершину стека значение из переменной под индексом 2.

    invokevirtual #3. Находит метод в пуле под #3, снимает требуемое количество значений из вершины стека для использования как параметры, снимает ссылку на объект и выполняет метод. Если метод что-то возвращает, кладет обратно на вершину стека.

    Как это выглядит в динамике (анимация):

    что такое byte code java. image loader. что такое byte code java фото. что такое byte code java-image loader. картинка что такое byte code java. картинка image loader.

    Реализация if

    Рассмотрим такой код:

    что такое byte code java. 1d1a4ee3bafe76dec8e549f6a2fe434e. что такое byte code java фото. что такое byte code java-1d1a4ee3bafe76dec8e549f6a2fe434e. картинка что такое byte code java. картинка 1d1a4ee3bafe76dec8e549f6a2fe434e.

    Реализация циклов

    Циклы стандартно реализуются аналогично if.

    Рассмотрим исходный код и его байткод:

    Реализация switch

    что такое byte code java. 042dbadff55bdc0ba5def0371316fed2. что такое byte code java фото. что такое byte code java-042dbadff55bdc0ba5def0371316fed2. картинка что такое byte code java. картинка 042dbadff55bdc0ba5def0371316fed2.

    Реализация throw

    При выполнении он выведет:

    Здесь добавилась Exception table, в которой строки отсортированы таким образом, что виртуальная машина проверяет соответствие строки и вида исключения сверху вниз с последней точки, где она остановилась.

    Когда мы дошли до 9 строчки, виртуальная машина выбросила исключение. И начала смотреть в Exception table. Первая запись удовлетворяет условиям использования (строчка 9 находится в интервале от 0 до 10 и указан RuntimeException) и поэтому выполняется переход на строчку 10.

    что такое byte code java. 333c3b66ff3001f775bb50978f17c1c3. что такое byte code java фото. что такое byte code java-333c3b66ff3001f775bb50978f17c1c3. картинка что такое byte code java. картинка 333c3b66ff3001f775bb50978f17c1c3.

    Дальше мы доходим до строчки 31 и снова выполняется выброс исключения. Смотреть мы теперь начинаем с 2 строчки ExceptionTable. Она нам не подходит и поэтому переходим на 3, которая подходит, и выполняем переход на 32 строчку.

    что такое byte code java. 6641b78ace251d31fa4ddf0813a0de94. что такое byte code java фото. что такое byte code java-6641b78ace251d31fa4ddf0813a0de94. картинка что такое byte code java. картинка 6641b78ace251d31fa4ddf0813a0de94.

    Вызовы методов (opcode: invokestatic, invokespecial, invokevirtual, invokeinterface, invokedynamic)

    invokestatic

    Используется для вызова статического метода. (Используется статическое связывание /Static Dispatch)

    invokespecial

    Используется для прямого вызова методов объекта текущего класса, конструкторов и методов родительского класса (Используется статическое связывание/Static Dispatch).

    При этом первым параметром передается ссылка на объект.

    Bytecode для конструктора класса Son

    что такое byte code java. 1c024a16d12f6a0ee3f782078593ab59. что такое byte code java фото. что такое byte code java-1c024a16d12f6a0ee3f782078593ab59. картинка что такое byte code java. картинка 1c024a16d12f6a0ee3f782078593ab59.

    invokevirtual

    Используется для вызова методов класса, при этом используется динамический поиск какой метод вызывать, основываясь на классе (Dynamic Dispatch). Так как методы могут быть переопределены, то сначала проверяется наличие метода в переданном классе, потом в родительском и так далее. Для поиска в HotSpot используется специальная таблица методов. Подробности можно посмотреть тут. При этом первым параметром передается ссылка на объект.

    Немного изменим предыдущий пример

    Bytecode для конструктора класса Son

    Теперь в строчках 5 и 10 используется invokevirtual.

    invokeinterface

    Используется для вызова методов интерфейса (Dynamic Dispatch). При этом первым параметром передается ссылка на объект.

    На 9 строчке вызывается метод интерфейса

    invokedynamic

    Вызов динамически-вычисляемых call sites. Сейчас, например, используется в Java для создания объектов для лямбд. Описание, как работает данный opcode, займет не одну статью и лучше всего посмотреть тут

    Справочник основных opcode

    Полная и единственно достоверная информация находится на сайте Oracle.

    aconst_null (0x1)

    Положить на стек null

    Формат: dload index

    Источник

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

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