Что такое JIT и как он влияет на поведение приложения в Java?
Что проверяют
Понимание того, как JVM на самом деле исполняет код, и практических следствий: почему первые запросы медленнее, почему замеры без прогрева врут, откуда берутся просадки в установившемся режиме.
Как отвечать
JVM стартует с интерпретации байт-кода и попутно считает, сколько раз вызван метод и сколько раз прокручен цикл. Горячий участок отдаётся JIT-компилятору, который переводит его в машинный код. В HotSpot компиляция многоуровневая: C1 компилирует быстро и собирает профиль, C2 компилирует долго, зато агрессивно. Работа идёт в фоновых потоках, а длинный цикл может быть подменён скомпилированной версией прямо во время исполнения.
Оптимизации, которые стоит назвать: инлайнинг, открывающий дорогу всем остальным; анализ убегания, позволяющий не размещать объект в куче; устранение проверок границ; удаление мёртвого кода. Ключевое слово для сильного ответа это спекулятивность: компилятор опирается на собранный профиль и допускает, что ветка не исполняется, а у интерфейса одна реализация. Допущение нарушено, значит происходит деоптимизация, метод возвращается в интерпретатор и компилируется заново.
Следствия для приложения: после старта нужен прогрев, поэтому трафик на свежий узел подают постепенно; бенчмарки пишут на JMH с прогревочными итерациями; сборка в нативный образ даёт мгновенный старт ценой потолка производительности.
Где спотыкаются
Говорят, что Java компилируется в машинный код при запуске программы. Компилируется не всё и не при запуске: интерпретатор работает с первой секунды, а в машинный код уезжают только горячие методы, набравшие счётчики.
Меряют производительность голым циклом с засечкой времени. Без прогрева замер попадает в интерпретатор, а иногда компилятор выбрасывает цикл целиком, потому что результат никуда не используется, и получается неправдоподобно быстрое время.
Считают JIT односторонним ускорением и не знают про деоптимизацию. Новая реализация интерфейса, неожиданный тип или ранее не исполнявшаяся ветка обесценивают скомпилированный код, и производительность проседает без единого изменения в коде.