Архитектура набора команд [ править ]
JVM является одновременно стековой и регистровой машиной . Каждый для вызова метода имеет «стек операндов» и массив «локальных переменных». : 2.6 Стек операндов используется для операндов для вычислений и для получения возвращаемого значения вызываемого метода, в то время как локальные переменные служат той же цели, что и регистры, и также используются для передачи аргументов метода. Максимальный размер стека операндов и массива локальных переменных, вычисляемый компилятором, является частью атрибутов каждого метода. : 4.7.3 Каждое значение может иметь независимый размер от 0 до 65 535, где каждое значение составляет 32 бита. итипы, которые являются 64 -битными , занимают две последовательные локальные переменные : 2.6.1 (которые не должны быть выровнены по 64-битным в массиве локальных переменных) или одно значение в стеке операндов (но считаются как две единицы в глубина стопки). : 2.6.2
Набор инструкций
Каждый байт-код состоит из одного байта, который представляет код операции , а также нуля или более байтов для операндов. : 2,11
Из 256 возможных кодов операций длиной в байт по состоянию на 2015 год 202 используются (~ 79%), 51 зарезервированы для будущего использования (~ 20%), а 3 инструкции (~ 1%) постоянно зарезервированы для реализаций JVM для использовать. : 6.2 Два из них ( и ) должны обеспечивать ловушки для программного и аппаратного обеспечения, зависящего от реализации, соответственно. Третий используется отладчиками для реализации точек останова.
Инструкции делятся на несколько широких групп:
- Загрузить и сохранить (например , )
- Арифметика и логика (например , )
- Преобразование типа (например , )
- Создание и управление объектами ( , )
- Управление стеком операндов (например , )
- Передача управления (например , )
- Вызов и возврат метода (например , )
Также есть несколько инструкций для ряда более специализированных задач, таких как генерация исключений, синхронизация и т. Д.
Многие инструкции имеют префиксы и / или суффиксы, относящиеся к типам операндов, с которыми они работают. : 2.11.1 Это следующие:
Префикс Суффикс | Тип операнда |
---|---|
целое число | |
длинная | |
короткая | |
байт | |
символ | |
плавать | |
двойной | |
Справка |
Например, добавит два целых числа, а два — двойных. , И инструкции могут также принимать суффикс формы , где п представляет собой число от 0-3 для и . Максимальный п для различена по типу.
В инструкции нажать значение указанного типа в стек. Например, поместит в стек целое число (32-битное значение) со значением 5, а двойное (64-битное значение с плавающей запятой) со значением 1 в стек. Также есть , который подталкивает ссылку. П для и инструкции определяет индекс в массиве локальной переменной к нагрузке от или магазина к. Инструкция толкает объект в локальной переменной 0 на стек (обычно это объект). сохраняет целое число наверху стека в локальную переменную 1. Для локальных переменных, превышающих 3, суффикс отбрасывается, и должны использоваться операнды.
Стандартные опции
Одним из наиболее часто используемых стандартных параметров команды javac является -d , указывающий каталог назначения для сгенерированных файлов классов . Если тип не является частью пакета по умолчанию, создается структура каталогов, отражающая имя пакета, чтобы сохранить файл класса этого типа.
Давайте выполним следующую команду в каталоге, содержащем структуру, представленную в предыдущем разделе:
javac -d javac-target com/baeldung/javac/Data.java
Компилятор javac сгенерирует файл класса javac-target/com/baeldung/javac/Data.class
Обратите внимание, что в некоторых системах javac не создает автоматически целевой каталог, который в данном случае является javac-target. Поэтому, возможно, нам придется сделать это вручную
Вот несколько других часто используемых вариантов:
- -cp (или -classpath , –class-path ) – указывает, где можно найти типы, необходимые для компиляции наших исходных файлов. Если этот параметр отсутствует, а переменная среды CLASSPATH не задана, вместо этого используется текущий рабочий каталог (как это было в приведенном выше примере).
- -p (или –путь к модулю ) – указывает расположение необходимых прикладных модулей. Эта опция применима только к Java 9 и выше – пожалуйста, обратитесь к этому учебнику для руководства по системе модулей Java 9.
Если мы хотим знать, что происходит в процессе компиляции, например, какие классы загружаются и какие компилируются, мы можем применить параметр -verbose .
Последний стандартный вариант, который мы рассмотрим, – это файл аргументов. Вместо того, чтобы передавать аргументы непосредственно инструменту javac , мы можем хранить их в файлах аргументов . Имена этих файлов с префиксом “@ “ затем используются в качестве аргументов команды.
Когда команда javac встречает аргумент , начинающийся с’@ ‘ , она интерпретирует следующие символы как путь к файлу и расширяет содержимое файла в список аргументов. Пробелы и символы новой строки могут использоваться для разделения аргументов, включенных в такой файл аргументов.
Предположим, что у нас есть два файла с именами options и types в каталоге javac-args со следующим содержимым:
Файл options :
-d javac-target -verbose
Файл types :
com/baeldung/javac/Data.java
Мы можем скомпилировать тип Data , как и раньше, с подробными сообщениями, напечатанными на консоли, выполнив эту команду:
javac @javac-args/options @javac-args/types
Вместо того, чтобы хранить аргументы в отдельных файлах, мы также можем хранить их все в одном файле .
Предположим, что в каталоге javac-args есть файл с именем arguments :
-d javac-target -verbose com/baeldung/javac/Data.java
Давайте передадим этот файл в javac , чтобы получить тот же результат, что и с двумя отдельными файлами до
javac @javac-args/arguments
Обратите внимание, что варианты, которые мы рассмотрели в этом разделе, являются наиболее распространенными. Для получения полного списка стандартных javac опций ознакомьтесь с
Что такое компилируемый язык программирования?
#include int main() { printf("Hello World"); }
Выше приведен простой пример программы, написанной на языке программирования C. Это пример компилируемого языка программирования. Чтобы выполнить код, его необходимо запустить с помощью компилятора. Для этого я использую следующую команду Linux:
gcc helloworld.c -o hello
Приведенная выше команда превращает код из формата, удобного для восприятия человеком, в машинный код, который может выполнить компьютер. gcc сам является скомпилированной программой (компилятор gnu c).
Скомпилированную программу можно выполнить, просто запустив имя программы следующим образом:
./hello
Преимущества использования компилятора заключаются в том, что он обычно работает быстрее, чем интерпретируемый код, так как ему не нужно обрабатывать код «на лету» во время работы приложения.
Кроме этого, скомпилированная программа будет проверена на наличие ошибок во время компиляции. Если есть команды, которые не понравились компилятору, то о них будет сообщено. Это позволяет исправлять все ошибки перед запуском программы.
Но то, что программа скомпилирована успешно, еще не означает, что она будет работать так, как вы ожидаете. Поэтому все равно нужно протестировать приложение.
Ничто не идеально. Если есть программа на компилируемом языке С, скомпилированная на компьютере, работающем Linux, я не могу копировать эту скомпилированную программу на Windows и рассчитывать, что исполняемый файл будет выполнен.
Чтобы запустить ту же программу на Windows, нужно будет снова скомпилировать ее, используя компилятор C на компьютере под управлением Windows.
Что такое интерпретируемый язык?
print ("hello world")
Приведенный выше код представляет собой программу на языке python, которая отображает слова «hello world».
Для выполнения кода нужно его компилировать сначала. Вместо этого я могу просто запустить следующую команду:
python helloworld.py
Приведенный выше код не нужно компилировать. Но необходимо, чтобы python был установлен на компьютере, на котором будет работать скрипт.
Интерпретатор python принимает удобный для восприятия человеком код и превращает его в промежуточное «состояние», прежде чем сформировать то, что может прочитать ПК. Все это происходит за кадром, и пользователь увидит только слова «hello world».
Принято считать, что интерпретируемый код будет работать медленнее, чем скомпилированный код, потому что он должен проходить этап преобразования кода в отличие от скомпилированный кода, который просто выполняется.
Хотя это может показаться недостатком, существует ряд причин, по которым интерпретируемые языки полезны. Одна из них состоит в том, что гораздо проще выполнить программу, написанную на Python, в Linux, Windows и OSX. Просто убедитесь, что Python установлен на компьютере, на котором вы хотите запустить скрипт.
Еще одно преимущество заключается в том, что код всегда доступен для чтения, и его можно легко изменить. В случае со скомпилированным кодом нужно найти, где находится код, изменить его, скомпилировать и заново запустить программу.
В случае использования интерпретируемого кода вы открываете программу, меняете ее, и она готова к работе.
Так какой же язык использовать?
Сомневаюсь, что выбор языка программирования для изучения будет определен тем, что вы узнали, какие языки являются компилируемыми.
Несмотря на то, что некоторые языки явно умирают, такие как COBOL, Visual Basic и ActionScript, есть и другие, которые были на грани вымирания, но резко вернулись на прежнее положение, как например, JavaScript.
В общем, мой совет заключается в том, что если вы используете Linux, вам следует изучать Java, Python или C, а если вы используете Windows, изучаете .NET и AngularJS.
Пожалуйста, оставляйте ваши отзывы по текущей теме статьи. За комментарии, дизлайки, отклики, подписки, лайки огромное вам спасибо!
МЛМария Логутенкоавтор-переводчик
Поддержка динамических языков [ править ]
Виртуальная машина Java обеспечивает некоторую поддержку для динамически типизированных языков . Большая часть существующего набора инструкций JVM является статически типизированной — в том смысле, что сигнатуры вызовов методов проверяются во время компиляции , без механизма, чтобы отложить это решение до времени выполнения или выбрать отправку метода с помощью альтернативного подхода.
JSR 292 ( Поддержка динамически типизированных языков на платформе Java ) добавил новую инструкцию на уровне JVM, чтобы разрешить вызов метода, основанного на динамической проверке типа (вместо существующей инструкции статической проверки типа ). Vinci Machine Da является прообразом реализации виртуальной машины , что хосты JVM расширений , направленных на поддержку языков динамических. Все JVM, поддерживающие JSE 7, также включают код операции.
Решение
Этот метод компиляции работает, его легко запустить и запустить, и он, по крайней мере, устраняет накладные расходы на интерпретацию. Но это приводит к довольно большим объемам кода и довольно ужасной производительности. Одна большая проблема заключается в том, что он транслитерирует операции стека 1: 1, хотя целевой компьютер (x86) является регистр машина. Как вы можете видеть в размещенном вами фрагменте (а также любой другой код), это всегда приводит к нескольким кодам операций манипуляции стека для каждый операция, поэтому он использует регистры — черт возьми, весь ISA — примерно настолько неэффективно, насколько это возможно.
Вы Можно также поддерживают сложные потоки управления, такие как исключения. Это не очень отличается от реализации в интерпретаторе. Если вы хотите хорошую производительность, вы не хотите выполнять работу каждый раз, когда вы входите или выходите из блок. Существуют схемы, позволяющие этого избежать, используемые как C ++, так и другими JVM (ключевое слово: обработка исключений с нулевой стоимостью или на основе таблиц). Они довольно сложны и сложны в реализации, понимании и отладке, поэтому сначала вам нужно выбрать более простую альтернативу. Просто имейте это в виду.
Что касается сгенерированного кода: первая оптимизация, которая вам почти наверняка понадобится, — это преобразование операций стека в трехадресный код или в другое представление, использующее регистры. Есть несколько работ по этому вопросу и реализации этого, поэтому я не буду подробно останавливаться, если вы не хотите, чтобы я это сделал. Затем, конечно, вам нужно отобразить эти виртуальные регистры на физические регистры. Распределение регистров является одной из наиболее хорошо изученных тем в конструкциях компилятора, и существует по крайней мере полдюжины эвристик, которые достаточно эффективны и достаточно быстры для использования в компиляторе JIT. Один из примеров, который стоит передо мной, — это распределение регистров с линейным сканированием (специально для компиляции JIT).
Кроме того, большинство JIT-компиляторов, ориентированных на производительность сгенерированного кода (в отличие от быстрой компиляции), используют один или несколько промежуточных форматов и оптимизируют программы в этой форме. Это в основном ваш прогон комплекта оптимизации компилятора, включая такие ветераны, как постоянное распространение, нумерация значений, повторная ассоциация, движение инвариантного кода цикла и т. Д. — эти вещи не только просты для понимания и реализации, они также были описаны за тридцать лет литературы вплоть до учебников и википедии.
Код, который вы получите с помощью вышеупомянутого, будет очень хорош для строкового кода, использующего примитивы, массивы и поля объекта. Однако вы вообще не сможете оптимизировать вызовы методов. Каждый метод является виртуальным, что означает, что встроенные или даже перемещаемые вызовы методов (например, вне цикла) в принципе невозможны, за исключением очень особых случаев. Вы упомянули, что это для ядра. Если вы можете согласиться с использованием подмножества Java без динамической загрузки классов, вы можете добиться большего успеха (но это будет нестандартно), предполагая, что JIT знает все классы. Затем вы можете, например, обнаружить листовые классы (или, в более общем случае, методы, которые никогда не переопределяются) и встроить их.
Если вам нужна динамическая загрузка классов, но вы ожидаете, что она будет редкой, вы также можете добиться большего, хотя это требует больше работы. Преимущество состоит в том, что этот подход обобщает другие вещи, например, полное исключение операторов регистрации. Основная идея заключается в специализации кода, основанного на некоторых предположениях (например, что это не меняется или что новые классы не загружаются), то де-оптимизация если эти предположения нарушаются. Это означает, что вам иногда придется перекомпилировать код во время его работы (это жесткий, но не невозможно).
Если вы пойдете дальше по этому пути, его логический вывод — это компиляция JIT на основе трассировки, которая имеет был применен к Java, но AFAIK не оказался лучше JIT-компиляторов на основе методов. Это более эффективно, когда вам нужно сделать десятки или сотни предположений, чтобы получить хороший код, как это происходит с высокодинамичными языками.
5
Преимущества и недостатки
Каждый из высокоуровневых языков вне зависимости от типа (компилируемый или интерпретируемый) обладает определенными свойствами. Это в значительной мере относится и к методу исполнения программ, написанных на том или ином диалекте. К достоинствам интерпретируемых языков относят:
- Кроссплатформенность. Они могут работать с различными операционными системами на разных аппаратных платформах.
- Динамическая типизация. Позволяет существенно упростить процесс создания программ, в которых используются переменные данные.
- Возможность пошагового отслеживания выполняемых алгоритмов и изменения программ непосредственно по время их реализации.
- Снижение трудозатрат на написание приложений и их последующую отладку.
Одним из основных недостатков интерпретируемых языков является относительно невысокая скорость выполнения написанных на них программ. По оценкам специалистов приложения на Python или PHP обрабатываются в отдельных случаях на два порядка медленнее, чем их аналоги на C++.
Преимущества и недостатки компилируемых и интерпретируемых языков
Языки высокого уровня, относящиеся к классу компилируемых, наряду с большой скоростью обработки имеют ряд иных преимуществ:
- В ходе предварительной обработки проводится проверка на наличие ошибок и внутренних противоречий. В случае выявления таковых появляется сообщение для пользователя, который получает возможность исправить ее до запуска.
- После компиляции сразу получается набор из машинных инструкций (машинный код), в котором есть все необходимое для центрального процессора. Этим и определяется высокая скорость их работы.
Языки компилируемого типа имеют и ряд недостатков:
- Необходимость предварительного тестирования успешно скомпилированного приложения. Это требует дополнительных временных затрат и внимания со стороны программиста.
- Исходный код, который скомпилированный для операционной системы Windows, не может быть запущен на Linux и наоборот. Для каждой ОС необходимо создавать отдельный исполняемый файл с использованием соответствующего служебного ПО.
Разница между интерпретируемыми высокоуровневыми языками и компилируемыми состоит в способе обработки процессором написанных на них программ. Скорость процесса в значительной мере зависит от производительности каждого конкретного компьютера или мобильного устройства.
Дополнительные опции
Дополнительные параметры javac -это нестандартные параметры, которые специфичны для текущей реализации компилятора и могут быть изменены в будущем. Поэтому мы не будем подробно рассматривать эти варианты.
Однако есть вариант, который очень полезен и заслуживает упоминания, -Xlint . Для получения полного описания других javac дополнительных опций перейдите по .
Опция -Xlint позволяет нам включать предупреждения во время компиляции . Существует два способа указать этот параметр в командной строке:
- -Xlint – запускает все рекомендуемые предупреждения
- -Xlint:клавиша* – включает определенные предупреждения
Вот некоторые из самых удобных -Xlint клавиш:
- rawtypes – предупреждает об использовании необработанных типов
- unchecked – предупреждает о непроверенных операциях
- static – предупреждает о доступе к статическому члену от члена экземпляра
- cast – предупреждает о ненужных бросках
- serial – предупреждает о том, что сериализуемые классы не имеют serialVersionUID
- fallthrough – предупреждает о провале в операторе switch
Теперь создайте файл с именем xl в tops в каталоге javac-args со следующим содержимым:
-d javac-target -Xlint:rawtypes,unchecked com/baeldung/javac/Data.java
При выполнении этой команды:
javac @javac-args/xlint-ops
мы должны увидеть rawtypes и непроверенные предупреждения:
com/baeldung/javac/Data.java:7: warning: found raw type: ArrayList List textList = new ArrayList(); ^ missing type arguments for generic class ArrayList where E is a type-variable: E extends Object declared in class ArrayList com/baeldung/javac/Data.java:7: warning: unchecked conversion List textList = new ArrayList(); ^ required: List found: ArrayList ...
Сравнение производительности
Давайте рассмотрим, как компиляция JIT улучшает производительность выполнения Java.
6.1. Тест производительности Фибоначчи
Мы будем использовать простой рекурсивный метод для расчета числа n-th Fibonacci:
private static int fibonacci(int index) { if (index <= 1) { return index; } return fibonacci(index-1) + fibonacci(index-2); }
Для того, чтобы измерить преимущества производительности для повторных вызовов метода, мы забудем метод Фибоначчи 100 раз:
for (int i = 0; i < 100; i++) { long startTime = System.nanoTime(); int result = fibonacci(12); long totalTime = System.nanoTime() - startTime; System.out.println(totalTime); }
Во-первых, мы будем собирать и выполнять Java-код обычно:
$ Java Фибоначчи.java
Затем мы выполним тот же код с отключенным компилятором JIT:
$ Java Фибоначчи.java
Наконец, мы будем реализовывать и запускать тот же алгоритм в C и JavaScript для сравнения.
6.2. Результаты тестирования производительности
Давайте посмотрим на измеренные средние показатели в наносекундах после запуска рекурсивного теста Фибоначчи:
- Java с помощью компилятора JIT – 2726 нс – самый быстрый
- Java без компилятора JIT – 17965 ns – 559% медленнее
- Без оптимизации O2 – 9435 нс – на 246% медленнее
- Си-2 с оптимизацией O2 – 3639 нс – на 33% медленнее
- JavaScript – 22998 нс – на 743% медленнее
В этом примере Производительность Java более чем на 500% лучше с помощью компилятора JIT . Тем не менее, это займет несколько работает для компилятора JIT для удара в.
Интересно, что Java выполнена на 33% лучше, чем код C, даже если C-код компилирован с включенным флагом оптимизации O2. Как и ожидалось, В первые несколько запусков СЗ выступил намного лучше, , когда Java все еще интерпретировалась.
Java также превзошла эквивалентный код JavaScript с узел, который также использует компилятор JIT. Результаты показывают более чем на 700% лучшую производительность. Основная причина в том, Компилятор JIT java стартует гораздо быстрее, чем .
Рабочий цикл программы
При использовании любого языка программирования существует определенный рабочий цикл создания кода. Вы пишете его, запускаете, находите ошибки и отлаживаете. Таким образом, вы переписываете и дописываете программу, проверяете ее. То, о чем пойдет речь в этой статье, это «запускаемая» часть программы.
Когда пишете программу, вы хотите, чтобы ее инструкции работали на компьютере. Компьютер обрабатывает информацию с помощью процессора, который поэтапно выполняет инструкции, закодированные в двоичном формате. Как из выражения «a = 3;» получить закодированные инструкции, которые процессор может понять?
Мы делаем это с помощью компиляции. Существует специальные приложения, известные как компиляторы. Они принимают программу, которую вы написали. Затем анализируют и разбирают каждую часть программы и строят машинный код для процессора. Часто его также называют объектным кодом.
На одном из этапов процесса обработки задействуется компоновщик, принимающий части программы, которые отдельно были преобразованы в объектный код, и связывает их в один исполняемый файл. Вот схема, описывающая данный процесс:
Конечным элементом этого процесса является исполняемый файл. Когда вы запускаете или сообщаете компьютеру, что это исполняемый файл, он берет первую же инструкцию из него, не фильтрует, не преобразует, а сразу запускает программу и выполняет ее без какого-либо дополнительного преобразования. Это ключевая характеристика процесса компиляции — его результат должен быть исполняемым файлом, не требующим дополнительного перевода, чтобы процессор мог начать выполнять первую инструкцию и все следующие за ней.
Первые компиляторы были написаны непосредственно через машинный код или с использованием ассемблеров. Но цель компилятора очевидна: перевести программу в исполняемый машинный код для конкретного процессора.
Некоторые языки программирования разрабатывались с учетом компиляции. C, например, предназначался для того, чтобы дать возможность программистам с легкостью реализовать разные вещи. Но в итоге он разрабатывался таким образом, чтобы его можно было легко перевести на машинный код. Компиляция в программировании это серьезно!
Не все языки программирования учитывают это в своей концепции. Например, Java предназначался для запуска в «интерпретирующей» среде, а Python всегда должен интерпретироваться.
Архитектура набора команд
JVM является одновременно стековой и регистровой машиной . Каждый для вызова метода имеет «стек операндов» и массив «локальных переменных». Стек операндов используется для операндов для вычислений и для получения возвращаемого значения вызываемого метода, в то время как локальные переменные служат той же цели, что и регистры, а также используются для передачи аргументов метода. Максимальный размер стека операндов и массива локальных переменных, вычисляемый компилятором, является частью атрибутов каждого метода. Каждый может иметь независимый размер от 0 до 65 535 значений, где каждое значение составляет 32 бита. и типы, которые являются 64-битными, занимают две последовательные локальные переменные (которые не должны быть выровнены по 64-битному в массиве локальных переменных) или одно значение в стеке операндов (но считаются как две единицы в глубине стека) .
Набор инструкций
Каждый байт-код состоит из одного байта, который представляет код операции , а также нуля или более байтов для операндов.
Из 256 возможных кодов операций длиной в байт по состоянию на 2015 год 202 используются (~ 79%), 51 зарезервированы для будущего использования (~ 20%), а 3 инструкции (~ 1%) постоянно зарезервированы для реализаций JVM для использовать. Два из них ( и ) предназначены для обеспечения ловушек для программного и аппаратного обеспечения, зависящего от реализации, соответственно. Третий используется отладчиками для реализации точек останова.
Инструкции делятся на несколько широких групп:
- Загрузить и сохранить (например , )
- Арифметика и логика (например , )
- Преобразование типа (например , )
- Создание и управление объектами ( , )
- Управление стеком операндов (например , )
- Передача управления (например , )
- Вызов и возврат метода (например , )
Также есть несколько инструкций для ряда более специализированных задач, таких как генерация исключений, синхронизация и т. Д.
Многие инструкции имеют префиксы и / или суффиксы, относящиеся к типам операндов, с которыми они работают. Это следующие:
Префикс Суффикс | Тип операнда |
---|---|
целое число | |
длинный | |
короткая | |
байт | |
персонаж | |
плавать | |
двойной | |
ссылка |
Например, добавит два целых числа, а два — двойных. , И инструкции могут также принимать суффикс формы , где п представляет собой число от 0-3 для и . Максимальный п для различена по типу.
В инструкции нажать значение указанного типа в стек. Например, поместит в стек целое число (32-битное значение) со значением 5, а двойное (64-битное значение с плавающей запятой) со значением 1 в стек. Также есть , который подталкивает ссылку. П для и инструкции определяет индекс в массиве локальной переменной к нагрузке от или магазина к. Инструкция толкает объект в локальной переменной 0 на стек (обычно это объект). сохраняет целое число наверху стека в локальную переменную 1. Для локальных переменных, превышающих 3, суффикс отбрасывается, и необходимо использовать операнды.
6 ответов
Реализации Java обычно используют двухэтапный процесс компиляции. Исходный код Java компилируется до байт-кода компилятором Java. Байт-код выполняется виртуальной машиной Java (JVM). Современные JVM используют метод, называемый Just-in-Time (JIT) compilation , для компиляции байт-кода в собственные инструкции, понятные аппаратному процессору, на лету во время выполнения.
Некоторые реализации JVM могут выбрать интерпретацию байт-код вместо JIT-компиляции его в машинный код и его непосредственного запуска. Хотя он по-прежнему считается «интерпретатором», он сильно отличается от интерпретаторов, которые читают и выполняют исходный код высокого уровня (то есть в этом случае исходный код Java не интерпретируется напрямую, а байт-код, выводимый компилятором Java, интерпретируется. )
Технически возможно заранее скомпилировать Java до нативного кода и запустить полученный двоичный файл. Также можно напрямую интерпретировать код Java.
Подводя итог, в зависимости от среды выполнения, байт-код может быть:
- скомпилирован заранее и выполнен как собственный код (аналогично большинству компиляторов C ++);
- скомпилирован точно в срок и выполнен
- интерпретирован
- выполняется непосредственно поддерживаемым процессором (байт-код — это собственный набор инструкций некоторых процессоров)
ответ дан 23 November 2019 в 22:56
Термины «интерпретируемый язык» или «компилируемый язык» «не имеют смысла, потому что любой язык программирования может быть интерпретирован и / или скомпилирован.
Что касается существующих реализаций Java, большинство из них включают этап компиляции в байт-код, поэтому они включают компиляцию. Среда выполнения также может загружать байт-код динамически, поэтому всегда требуется некоторая форма интерпретатора байт-кода.
Этот интерпретатор, в свою очередь, может использовать или не использовать компиляцию для внутреннего кода.
В наши дни частичная своевременная компиляция используется для многих языков, которые когда-то считались «интерпретируемыми», например, Javascript.
ответ дан 23 November 2019 в 22:56
Java компилируется в байт-код, который затем передается в виртуальную машину Java, которая его интерпретирует.
ответ дан 23 November 2019 в 22:56
И то и другое. Сначала java скомпилирован (некоторые предпочли бы сказать «переведен») в байт-код, который затем либо компилируется, либо интерпретируется в зависимости от настроения JIT.
ответ дан 23 November 2019 в 22:56
Java — это скомпилированный язык программирования, но вместо того, чтобы компилировать прямо в исполняемый машинный код, он компилируется в промежуточную двоичную форму, называемую байтовым кодом JVM. Затем байт-код компилируется и / или интерпретируется для запуска программы.
ответ дан 23 November 2019 в 22:56
Java — это язык с байтовой компиляцией, предназначенный для платформы, называемой виртуальной машиной Java , которая основана на стеке и имеет несколько очень быстрых реализаций на многих платформах.
ответ дан 23 November 2019 в 22:56
Другие вопросы по тегам:
Что такое компилируемый язык программирования?
Приведенная выше команда превращает код из формата, удобного для восприятия человеком, в машинный код, который может выполнить компьютер. gcc сам является скомпилированной программой ( компилятор gnu c ).
Скомпилированную программу можно выполнить, просто запустив имя программы следующим образом:
Преимущества использования компилятора заключаются в том, что он обычно работает быстрее, чем интерпретируемый код, так как ему не нужно обрабатывать код « на лету » во время работы приложения.
Кроме этого, скомпилированная программа будет проверена на наличие ошибок во время компиляции. Если есть команды, которые не понравились компилятору, то о них будет сообщено. Это позволяет исправлять все ошибки перед запуском программы.
Но то, что программа скомпилирована успешно, еще не означает, что она будет работать так, как вы ожидаете. Поэтому все равно нужно протестировать приложение.
Что такое интерпретируемый язык?
Для выполнения кода нужно его компилировать сначала. Вместо этого я могу просто запустить следующую команду:
Приведенный выше код не нужно компилировать. Но необходимо, чтобы python был установлен на компьютере, на котором будет работать скрипт.
Интерпретатор python принимает удобный для восприятия человеком код и превращает его в промежуточное « состояние », прежде чем сформировать то, что может прочитать ПК. Все это происходит за кадром, и пользователь увидит только слова « hello world ».
Принято считать, что интерпретируемый код будет работать медленнее, чем скомпилированный код, потому что он должен проходить этап преобразования кода в отличие от скомпилированный кода, который просто выполняется.
Еще одно преимущество заключается в том, что код всегда доступен для чтения, и его можно легко изменить. В случае со скомпилированным кодом нужно найти, где находится код, изменить его, скомпилировать и заново запустить программу.
В случае использования интерпретируемого кода вы открываете программу, меняете ее, и она готова к работе.
Так какой же язык использовать?
Сомневаюсь, что выбор языка программирования для изучения будет определен тем, что вы узнали, какие языки являются компилируемыми.