JIT

Строго определенная JIT-виртуальная машина перед выполнением преобразовывает все байткоды в машинный код, но делает это в неторопливом стиле: JIT компилирует code path только тогда, когда знает, что code path будет сейчас выполняться (отсюда и название just-in-time компиляция). Этот подход дает возможность программам стартовать быстрее, поскольку не требуется длительная фаза компиляции перед возможным началом исполнения кода.

HotSpot

Основная виртуальная машина Java (JVM) как для клиентских, так и для серверных компьютеров, выпускаемая корпорацией «Oracle».

Для повышения производительности обладает технологиями динамической компиляции JIT и адаптивной оптимизации (that application code will be analyzed as it runs to detect performance bottlenecks, or “hot spots”. HotSpot will then compile those hot spots for a boost in performance).

Both implementations of HotSpot are distributed inside the JDK (Java Development Kit) package and the JRE (Java Runtime Environment) package.

Исполняющий процесс HotSpot объединяет интерпретацию, профилирование и динамическую компиляцию. Вместо преобразования всех байткодов в машинный код HotSpot начинает работу как интерпретатор и компилирует только “горячий” код, то есть код, выполняющийся наиболее часто. Во время выполнения он собирает данные анализа.

Клиентский и серверный компиляторы

HotSpot поставляется с двумя компиляторами: клиентским и серверным. По умолчанию используется клиентский компилятор.

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

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

HotSpot Client VM (C1)

The Client VM has been specially tuned to reduce application start-up time and memory footprint, making it particularly well suited for client environments.

HotSpot Server VM (C2)

The Server VM has been specially tuned to maximize peak operating speed. It is intended for running long-running server applications, for which having the fastest possible operating speed is generally more important than having the fastest possible start-up time.

On the Stack Replacement

Обычная компиляция случается когда JVM обнаруживает, что какой-то метод достаточно горячий, чтобы его имело смысл скомпилировать. Для этого с каждым методом связывается счетчик, который считает число вызовов метода, и число обратных переходов (backedge) - переходов “назад” по потоку инструкций (goto внутри этого метода), для отслеживания циклов например. Таким образом метод будет считаться горячим не только если он часто вызывается, но и если сам он вызывается не очень часто, но внутри него есть достаточно “тяжелые” циклы.

Когда счетчик перевалит за какой-то порог (скажем, 10 000) — последовательность байт-кодов метода ставится в очередь на компиляцию. При первой же возможности JIT до нее доберется, скомпилирует, и заменит ссылку в таблице методов на оптимизированную версию. И при очередном, 11 042-м вызове исполнение пойдет уже в скомпилированный и оптимизированный метод.

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

В таких ситуациях нужно уметь заменять версии метода прямо по ходу его выполнения - подмена “на стеке” (On the Stack Replacement, OSR).

Для реализации такого механизма нужно фиксировать некоторый набор safepoint-ов, обозначающие наиболее подходящие точки для компиляции (иначе задача становится труднее так как компиляция происходит из произвольной точки). Собственно, “обычный” (не-OSR) компилятор использует в качестве таких safepoint-ов границы между методами. OSR же добавляет возможность переключаться на backedge-ах циклов.