Рубрики
Без рубрики

Является ли Java компилирован или интерпретирован языком?

Автор оригинала: Daniel Strmecki.

1. Обзор

Языки программирования классифицируются на основе их уровней абстракции. Мы дифференцируют языки высокого уровня (Java, Python, JavaScript, C, Go), низкоуровневые (ассембер) и, наконец, машинный код.

Каждый языковой код высокого уровня, такой как Java, должен быть переведен на родной код машины для выполнения. Этот процесс перевода может быть как компиляцией, так и интерпретацией. Однако есть и третий вариант. Комбинация, которая стремится воспользоваться обоими подходами.

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

2. Составлено против Интерпретировано

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

2.1. Собранные языки

Собранные языки (C q, Go) преобразуются непосредственно в родной код машины по программе компилятора.

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

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

2.2. Интерпретированы языки

С другой стороны, в интерпретируемых языках (Python, JavaScript) нет шагов сборки. Вместо этого, переводчики работают на исходный код программы при его выполнении.

Интерпретируемые языки когда-то считались значительно медленнее, чем составленные языки. Однако с разработкой точно в срок (JIT) компиляции разрыв в производительности сокращается. Однако следует отметить, что компиляторы JIT превращают код из интерпретируемого языка в родной код машины по мере времени времени, которую выполняет программа.

Кроме того, мы можем выполнять интерпретируемый языковой код на нескольких платформах как Windows, Linux или Mac. Интерпретируемый код не имеет сходства с определенным типом архитектуры процессора.

3. Напишите один раз запустить в любом месте

Java и JVM были разработаны с портативностью в виду. Поэтому большинство популярных платформ сегодня могут запускать Java-код.

Это может звучать как намек на то, что Java является чисто интерпретируемый язык. Однако перед казнью Исходный код Java должен быть составлен в код . Bytecode – это специальный машинный язык, родом из JVM . JVM интерпретирует и выполняет этот код во время выполнения.

Это JVM, который построен и настроен для каждой платформы, которая поддерживает Java, а не наши программы или библиотеки.

Современные JVMs также имеют компилятор JIT. Это означает, что JVM оптимизирует наш код во время для получения аналогичных преимуществ производительности для составленного языка.

4. Компилятор Java

Явак инструмент командной строки компилирует исходный код Java в файлы класса Java содержащий нейтральный для платформы интегрид:

$ Javac HelloWorld.java

Файлы исходных кодов .java суффиксы, в то время как классные файлы, содержащие литкод, генерируются с помощью . класс Суффиксы.

5. Java Виртуальная машина

Собранные классные файлы (bytecode) могут быть выполнены виртуальной машиной Java (JVM):

$ Java HelloWorld Здравствуйте, Ява!

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

5.1. Обзор архитектуры

СПМ состоит из пяти подсистем:

  • Класс Загрузчик
  • Память JVM
  • Двигатель выполнения
  • Интерфейс родного метода и
  • Библиотека родных методов

5.2. Класс Загрузчик

СПМ использует эту Класс Загрузчик подсистемы для привести собранные файлы класса в Память JVM.

Помимо загрузки, ClassLoader также выполняет увязку и инициализацию. Это включает в себя:

  • Проверка tecode на любые нарушения безопасности
  • Выделение памяти для статических переменных
  • Замена символических ссылок памяти на исходные ссылки
  • Назначение исходных значений статическим переменным
  • Выполнение всех статичных блоков кода

5.3. Двигатель исполнения

Подсистема двигателя выполнения отвечает за чтение ютекода, преобразование его в родной код машины и его выполнение.

За выполнение отвечают три основных компонента, включая как переводчика, так и компилятора:

  • Поскольку JVM является нейтральным с точки зрения платформы, он использует переводчика для выполнения интегрирования
  • Компилятор JIT повышает производительность путем компиляции краткода в родной код для повторных вызовов метода
  • Сбор мусора собирает и удаляет все неучтеемые объекты

Движок выполнения использует интерфейс метода Native (JNI) для вызова родных библиотек и приложений.

5.4. Как раз вовремя Компилятор

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

Компилятор JIT не полностью заменяет переводчика. Двигатель выполнения по-прежнему использует его. Тем не менее, JVM использует компилятор JIT на основе того, как часто метод называется.

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

Профайлер является специальным компонентом компилятора JIT, ответственного за поиск горячих точек. JVM решает, какой код для компиляции JIT основан на информации профилирования, собранной во время выполнения.

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

6. Сравнение производительности

Давайте рассмотрим, как компиляция 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 стартует гораздо быстрее, чем .

7. Что следует учитывать

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

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

В этой статье мы сосредоточились на объяснении того, как все работает в HotSpot. HotSpot — это реализация Oracle с открытым исходным кодом с открытым исходным кодом. Graal VM также основан на HotSpot, поэтому применяются те же принципы.

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

8. Заключение

В этой статье мы рассмотрели Java и внутренние данные JVM. Наша цель состояла в том, чтобы определить, является ли Java компиляцией или интерпретируемой формулировкой. Мы исследовали компилятор Java и внутренние внутренние системы двигателя выполнения JVM.

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

Исходный код, который мы пишем на Java, сначала компилируется в bytecode во время процесса сборки. Затем JVM интерпретирует генерируемый код для выполнения. Тем не менее, JVM также использует компилятор JIT во время выполнения для улучшения производительности.

Как всегда, исходный код доступен более на GitHub .