Компиляция и интерпретация
Правильнее классифицировать не язык, а конкретную реализацию и путь выполнения программы. Один язык может иметь интерпретатор, JIT-компилятор и AOT-компилятор.
| Подход | Когда переводится код | Что исполняется |
|---|---|---|
| ahead-of-time compilation | до запуска | машинный код или промежуточное представление |
| interpretation | во время запуска, инструкция за инструкцией | исходный код или bytecode |
| just-in-time compilation | во время работы по профилю | скомпилированные горячие участки |
Путь Java
Main.java
│ javac
▼
Main.class (bytecode)
│ class loading + verification
▼
интерпретация → профилирование → JIT-компиляция горячего кодаjavac проверяет типы и переводит исходник в JVM bytecode. JVM сначала может интерпретировать методы, собирая профиль, а затем JIT-компилятор оптимизирует часто выполняемый код под конкретный процессор. Оптимизированный метод может быть деоптимизирован, если предположения перестали выполняться.
public static int sum(int[] values) {
int result = 0;
for (int value : values) {
result += value;
}
return result;
}Этот метод один и тот же в .class, но машинный код зависит от JVM, профиля нагрузки и архитектуры CPU.
Компромиссы
- AOT сокращает прогрев, но имеет меньше runtime-профиля;
- интерпретатор быстро начинает выполнение, но медленнее на горячем коде;
- JIT тратит CPU/память на компиляцию и требует прогрева, зато использует реальные профили;
- переносимость bytecode обеспечивается JVM, а не отсутствием компиляции.
На собеседовании
Java — компилируемый или интерпретируемый язык? Обычный HotSpot-путь сочетает компиляцию в bytecode, интерпретацию и JIT.
Почему benchmark надо прогревать? До JIT-компиляции и стабилизации профиля измеряется другой режим.
Что такое деоптимизация? Возврат от оптимизированного кода, когда его спекулятивные предположения стали неверны.
Bytecode — машинный код? Нет, это инструкции виртуальной машины.
Связано: Структура JDK, Class loader.