Байт код что это
Перейти к содержимому

Байт код что это

  • автор:

Как объяснить, что такое байткод? [закрыт]

Закрыт. На этот вопрос невозможно дать объективный ответ. Ответы на него в данный момент не принимаются.

Хотите улучшить этот вопрос? Переформулируйте вопрос так, чтобы на него можно было дать ответ, основанный на фактах и цитатах.

Закрыт 3 года назад .

Пытался объяснить начинающим инженерам, что такое байткод (в рамках пояснения принципов выполнения Java программ). Так вот, я пытаюсь стандартно объяснить, мол это что то между компиляцией и интерпретацией, типа каждая команда джавовского байт кода, это как несколько ассемблеровских комманд, но они смотрят на меня и говорят — не понятноооо! Они не программисты, не знают что такое ни компиляция, ни интерпретация, ни ассемблер, это я попытался на пальцах им объяснить, и вроде до них что-то дошло, а как можно на пальцах используя жизненные примеры объяснит принцип работы байткода?

Отслеживать
23.4k 3 3 золотых знака 49 49 серебряных знаков 70 70 бронзовых знаков
задан 18 мая 2013 в 20:37
vanyamelikov vanyamelikov
3,113 3 3 золотых знака 30 30 серебряных знаков 59 59 бронзовых знаков
Если они не программисты, то им это не нужно. Не тратьте время.
18 мая 2013 в 20:44
18 мая 2013 в 20:45

Я сам не программист(по образованию), сейчас стоит вопрос проведения расчета охлаждения камеры сгорания ракетного двигателя. Так вот я хочу дать троим студентам эту задачу, на трех разных языках, и посмотреть у кого лучше получиться. Языки: java-среда эклипс, Си++ — Visual Studio и Visual Basic да еще и 6. Сам я его накидал в MathCAD и MathLab. Думаю должен получиться хороший эксперимент!

18 мая 2013 в 20:51

Извините за прямоту — но складывается ощушение, будто отвечающие, сами до конца не понимают, кроме @KoVadim что такое байт код. Не надо мразу минусовать! Вдумайтесь в вопросе было, что необходимо обяснить байт код, при условии понимания небольшого понятий компиляции и интерпретации! А у многих определения можно отнести как к первому, так ко второму и третьему!

19 мая 2013 в 6:05

Хотел было уже написать, но заглянул в Википедию и понял, что ничего добавить не смогу. @vanyamelikov, а Ваши коллеги эту статью читали?

19 мая 2013 в 19:50

7 ответов 7

Сортировка: Сброс на вариант по умолчанию

А нужно объяснять очень просто. Используя их положение. Для начала показываем этим инженерам программу на Java. Например, классический HelloWorld. И спрашиваем — понятно ли? Скорее всего они скажут нет. Объясняем, что и специальной программе, которая исполняет жава код, тоже не понятно. Для этого нужно «разобрать по косточкам».

Теперь делаем «псевдотрасляцию» — как для машинистки (секретарши). Для HelloWorld’а она будет такая.

  • настроить окружение (в коде этого нет, но это автоматом) — приготовить бумагу, проверить катриджи.
  • взять из памяти строку «привет мир».
  • нижимая кнопки, побуквенно ввести сроку (здесь появился цикл:) ).
  • почистить все за собой и отнести бумагу заказчику.

Формально — это и есть простой байткод. Только это человеческий байткод. А если в нем стандартизировать все операции и занумеровать, то все может быть сведено к набору чисел. Теперь к реальному байткоду перейти просто.

Легко будет объяснить и переносимость. Если человек (секретарша) выучит все коды операций, то она сможет выполнить любую работу, главное, что бы была последовательность кодов. А инженеры могут попробовать спаять-сконструировать устройство, которое будет это исполнять.

Байт-код

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

Ваш провайдер знает о вас больше, чем ваша девушка? Присоединяйтесь и узнайте, как это остановить!

2 июня, 2023

PyPI-пакет смешал вредоносный код со скомпилированным для обхода средств защиты

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

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

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

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

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

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

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

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

Байт-код — это просто результат компиляции класса Java. Файл .class на самом деле представляет собой набор инструкций байт-кода, в которые преобразуется код. Он нуждается в интерпретаторе, таком как JVM, чтобы понимать и выполнять инструкции.

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

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

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

Следующая команда позволит увидеть фактический байт-код файла .class .

javap -c -p -v [path to the .class file]

Какие здесь флаги?

  • -c нужен для дизассемблирования класса Java.
  • -p нужен для раскрытия закрытых членов класса.
  • -v нужен для просмотра подробной информации, такой как размер стека и пул констант.

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

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

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

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

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

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

В массиве локальных переменных с индексацией от нуля первые индексы используются для хранения аргументов метода. После того, как они будут сохранены, в массив сохранятся другие локальные переменные. Если метод — не статический, а создаёт экземпляры, нулевой индекс будет зарезервирован для хранения ссылки this , которая указывает на экземпляр объекта для вызова метода.

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

public String sayHello(int num, String name) String hello = "Hello, " + name; 
return hello;
>

public static String sayHello(int num, String name) String hello = "Hello, " + name;
return hello;
>

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

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

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

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

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

aload_0 //отправляет ссылку на непримитивное значение данных в индексе 0 массива переменныхiload_2 //отправляет значение int в индекс 4 массива переменныхiconst_3 //отправляет int 3 в стекiadd //добавляет два самых верхних значения int в стекistore_3 //выводит результат операции добавления и сохраняет в индексе 6 массива переменных

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

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

package demo;

import java.util.ArrayList;
import java.util.List;

public class SimpleClass
private List evenNums;

public SimpleClass() evenNums = new ArrayList<>();
>

private boolean isEven(int num) return num % 2 == 0;
>

public void addEven(int num) if (isEven(num)) evenNums.add(num);
>
>
>

Скомпилируем класс с помощью команды javac и посмотрим байт-код с помощью javap . Результат выглядит так:

Compiled from "SimpleClass.java"
public class demo.SimpleClass private java.util.List evenNums;

public demo.SimpleClass();
Code:
0: aload_0
1: invokespecial #1 // метод java/lang/Object."":()V
4: aload_0
5: new #2 // класс java/util/ArrayList
8: dup
9: invokespecial #3 // метод java/util/ArrayList."":()V
12: putfield #4 // поле evenNums:Ljava/util/List;
15: return

private boolean isEven(int);
Code:
0: iload_1
1: iconst_2
2: irem
3: ifne 10
6: iconst_1
7: goto 11
10: iconst_0
11: ireturn

public void addEven(int);
Code:
0: aload_0
1: iload_1
2: invokespecial #5 // Метод isEven:(I)Z
5: ifeq 22
8: aload_0
9: getfield #4 // Поле evenNums:Ljava/util/List;
12: iload_1
13: invokestatic #6 // Метод java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
16: invokeinterface #7, 2 // Метод интерфейса java/util/List.add:(Ljava/lang/Object;)Z
21: pop
22: return
>

Посмотрев на инструкции байт-кода, вы обнаружите несколько знакомых команд, включая load и const . Остальное, однако, может даже сбить с толку.

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

Все не так страшно, как кажется. Попробуем деконструировать байт-код SimpleClasсs шаг за шагом. Начнем с самого простого метода — isEven .

private boolean isEven(int num) return num % 2 == 0;
>

Вот его байт-код:

private boolean isEven(int); 
Code:
0: iload_1
1: iconst_2
2: irem
3: ifne 10
6: iconst_1
7: goto 11
10: iconst_0
11: ireturn
  1. Во-первых, инструкция iload_1 помещает значение массива локальных переменных с индексом 1 в стек операндов. Поскольку метод isEven является методом экземпляра, ссылка на него хранится в нулевом индексе. Тогда легко понять, что значение, хранящееся в индексе 1, на самом деле будет принятым значением параметра int .
  2. iconst_2 помещает значение 2 в верхнюю часть стека операндов.
  3. Инструкция irem применяется для нахождения остатка от деления между двумя числами. Это инструкция, которая представляет логику оператора % . Она извлекает два самых верхних значения в стеке и помещает результат обратно в стек.
  4. Команда ifne сообщает JVM перейти к инструкции с заданным смещением (в данном случае — 10), если значение, обрабатываемое командой, не равно 0. Для реализации этой логики команда берет верхний элемент стека. Если переданное число было четным, то верхний элемент будет равен 0, и в этом случае JVM получает команду перейти к инструкции с индексом 6. Однако, если значение стека не равно нулю, что происходит, когда число нечетное, JVM переходит к инструкции с индексом 10.
  5. iconst_1 помещает значение int 1 в стек. Это происходит только в том случае, если результат irem равен 1. Здесь 1 представляет логическое значение true .
  6. goto говорит JVM перейти к инструкции, приведенной в смещении, что в данном случае равно 11. Инструкция goto применяется для перехода с одного места в таблице инструкций на другое.
  7. iconst_0 помещает в стек значение 0. Эта инструкция идет в дело, когда условие if оказывается ложным. Переданное значение 0 действует как логическое значение false . Инструкции 3, 6, 7 обрабатывают случай, когда условие if истинно.
  8. ireturn возвращает значение int в верхней части стека.

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

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

Опкоды — это такие команды, как iload , iconst и т.д. В зависимости от размера операндов размер байт-кода может варьироваться от одного байта до нескольких. Отсюда и пробелы в индексах таблицы инструкций. Единственная здесь двухбайтовая инструкция — ifne .

В байт-коде SimpleClass.class есть другие инструкции, такие как invokespecial , invokeinterface и invokestatic , которые в свою очередь являются инструкциями вызова метода.

Вывод

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

  • Сборка мусора в Java: что это такое и как работает в JVM
  • 9 советов, как выделиться среди Java-разработчиков
  • Состояния потоков в Java

Машинный код и байт код: на каком языке говорит ваша программа?

Java-университет

У тех, кто только начинает знакомиться с Java, довольно часто возникает путаница в понятиях машинный и байт код. Что они собой представляют? В чём различия? В короткой заметке мы постараемся максимально просто и понятно расписать их особенности, чтоб раз и навсегда закрыть этот вопрос.

Машинный код и байт код: на каком языке говорит ваша программа? - 1

Машинный код

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

Врожденная несовместимость

При этом далеко не все процессоры «говорят» на одном языке. Различия есть не только между архитектурами CISC и RISC, но и внутри этих «лагерей».

CISC (англ. Complex Instruction Set Computing) — концепция проектирования процессоров, которая характеризуется следующим набором свойств:

  • много команд, разных по длине;
  • много режимов адресации;
  • сложная кодировка инструкции.

В новых поколениях процессоров внедряют дополнительные наборы инструкций, которые моделям старшего поколения попросту неизвестны. Из-за этого программы, скомпилированные для одной архитектуры (или одного поколения процессоров) не могут работать на другом аппаратном обеспечении. Все это вынуждает заниматься перекомпиляцией программ для обеспечения их работы на других компьютерах. Впрочем, заново компилировать приходится не только из-за процессоров, но и еще из-за различий во взаимодействии программ и операционной системы. Именно из-за них невозможно запустить «виндовую» программу под Linux, а «линуксовую» под Windows.

Байт-код

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

JIT-компиляция (англ. Just-in-time compilation, компиляция «на лету») или динамическая компиляция (англ. dynamic translation) — это технология увеличения производительности программных систем, использующих байт-код, путём компиляции байт-кода в машинный код или в другой формат непосредственно во время работы программы. «Официально» в Java до 9-й версии был только JIT-компилятор. В Java 9 появился ещё один компилятор, причём компилирует он с опережением (AoT). Эта возможность позволяет компилировать классы Java в нативный код перед запуском на виртуальной машине. Данная функция предназначена для улучшения времени запуска и малых, и больших приложений, с ограниченным влиянием на максимальную производительность.

Для CISC процессоров некоторые инструкции могут объединяться в более сложные конструкции, поддерживаемые процессором, а для RISC – наоборот разбиваться на более простые последовательности команд.

Еще и виртуальная ОС

Впрочем, байт код содержит не только процессорные инструкции. В нем также содержится логика взаимодействия с виртуальной операционной системой, которая делает поведение приложения независящим от используемой на компьютере операционной системы. Это отлично видно в JVM, где работа с системными вызовами и GUI зачастую не зависят от ОС, на которой запущена программа. По большому счету JVM эмулирует запуск процесса программы, в отличие от решений вроде Virtual Box, которые создают только виртуальную систему/железо.

JVM одна такая?

Определенно нет. Тот же DotNet CLI это тоже виртуальная машина, которую чаще всего используют на компьютерах, работающих под Windows с x86 совместимыми процессорами. Впрочем существует ее реализация и под другие системы: приложения под него должны работать в Windows RT запущенной на ARM (RISC) совместимых процессорах, или можно запустить их на Linux/OSX в среде Mono, являющей сторонней (и потому не полностью совместимой) реализацией DotNet для этих платформ. Так что эта платформа, как и JVM, работает на разных процессорах и разных ОС. Существует еще множество похожих решений (как старых, так и новых): LLVM, Flash SWF, и другие. У некоторых языков программирования есть собственные виртуальные машины. К примеру, CPython компилирует исходники из PY в файлы PYC – скомпилированный (compiled) байт код который подготовлен к запуску в PVM. Или есть намного более древний пример — Lisp можно компилировать в файлы FASL (Fast Load). Фактически они содержат AST дерево, построенное генератором из исходного кода. Эти файлы могут быть прочитаны и запущены интерпретатором Lisp на разных платформах, или использованы для создания машинного кода для используемой на данный момент аппаратной архитектуры.

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

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