В продолжение темы про работу JVM.

Обычно исходный код компилируется в байткод компилятором языка. Потом проходит его верификация и линковка, после которых он попадает в интерпретатор. И уже интерпретатор переводит его в исполняемый (машинный) код. Хотя можно вообще все скомпилировать заранее, как в C: например, с некоторым ограничениями это позволяет сделать GraalVM.

Есть 4 уровня компиляции:

  1. Интерпретатор
  2. C1 без профилирования
  3. C1 с минимальным профилированием
  4. C1 с максимальным профилированием
  5. C2 со всеми оптимизациями

Интерпретатор выполняет байт-код максимально тупо, “построчно”. В процессе исполнения интерпретатор приблизительно считает, как часто вызывался каждый метод, и после достижения порога он переходит на следующий уровень компиляции — третий. Метод компилируется, в него добавляются счетчики, чтобы получить более точную картину нагрузки. Он исполняется быстрее, чем в интерпретаторе, но все равно медленно. Потом метод попадает на уровень C2. Однако компилятор C2 довольно медленный и не всегда успевает все сделать, поэтому перед попаданием на третий уровень, метод иногда тусит на втором, “в очереди” — исполнение побыстрее третьего, но тут меньше информации. Бывает, что компиляция в C2 невозможна — тогда профилирование выкидывается, и метод работает на первом уровне без профилирования. А иногда JVM решает, что метод очень простой, сразу закидывает его на первый уровень и больше не трогает.

Можно отключить C1 (уровни 1-3) совсем, тогда метод будет попадать из интерпретатора сразу на C2 — и так было до JVM 8: у “серверных” приложений был С2 (медленный старт, но быстрая работа), а у клиентских — C1 (быстрый старт, но медленнее работа).

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