JIT в PHP 8: когда он реально ускоряет, а когда бесполезен
JIT добавили в PHP 8.0 с обещанием роста производительности. На веб-запросах он часто не даёт ничего, а иногда мешает. Разбираем, где замеры показывают ускорение, а где включать его — потеря времени.

Когда в ноябре 2020 вышел PHP 8.0, одной из главных новостей стал JIT-компилятор. В презентациях мелькали цифры вроде трёхкратного роста. Потом владельцы сайтов на Laravel и WordPress включали opcache.jit, замеряли время ответа — и не видели разницы. Иногда время даже росло. Это не баг конфигурации. Так JIT в PHP и работает: он ускоряет счётные задачи и почти не трогает типичный веб-запрос, где всё упирается в базу и ввод-вывод.
Разберём на замерах, какой код JIT реально ускоряет, почему на веб-нагрузке эффект близок к нулю, и как проверить это на своём приложении, а не на синтетике из блога вендора. Актуально для PHP 8.0–8.3.
Что именно делает JIT в PHP
До PHP 8 конвейер был такой: исходник → байткод (opcode) → интерпретатор Zend VM исполняет байткод. OPcache кеширует байткод, чтобы не парсить файл на каждом запросе. Это дало основной прирост ещё в PHP 7 и никуда не делся.
JIT добавляет ещё один слой: часть горячего байткода компилируется в машинный код прямо во время исполнения, минуя интерпретацию Zend VM. Выигрыш появляется там, где VM тратит время на диспетчеризацию опкодов и на арифметику, — то есть в плотных циклах с числами.
Zend VM — виртуальная машина, которая исполняет байткод PHP по одному опкоду за шаг. На каждом шаге есть накладные расходы на выбор обработчика опкода. JIT убирает именно эти расходы для скомпилированных участков.
JIT в PHP — это не «ускоритель PHP вообще». Это ускоритель кода, который считает, а не ходит в базу, файлы и сеть. Веб-запрос обычно занимается вторым.
Где эффект есть, а где его нет
Ключевой факт: в большинстве веб-приложений процессорное время на исполнение самого PHP-кода — меньшая часть запроса. Основное время уходит на запросы к MySQL/PostgreSQL, обращения к Redis, вызовы внешних API, чтение шаблонов и сериализацию. JIT ни одну из этих операций не ускоряет, потому что они не считаются в Zend VM — они уходят в системные вызовы и ждут ответа.
- Ускоряет заметно: обработка изображений на чистом PHP, математика (матрицы, физика, финансовые расчёты), парсеры и лексеры, генерация фракталов и подобное — код, который крутит числа в циклах без обращений наружу.
- Почти не трогает: типичный запрос Laravel/Symfony/WordPress, где роутинг, ORM, рендер шаблона и запросы к БД. Здесь выигрыш обычно в пределах погрешности замера.
- Может замедлить: первые запросы после старта воркера — пока JIT профилирует и компилирует горячие участки, тратится дополнительное время. На короткоживущих процессах это заметно.
Как выглядят замеры
Синтетический тест на счётной нагрузке (алгоритм Мандельброта, миллионы итераций арифметики) на PHP 8.2 действительно ускоряется в разы при включённом tracing-режиме JIT. Это тот самый бенчмарк, который показывают в презентациях.
Тот же PHP на реальном запросе интернет-магазина — товар, категория, корзина, десяток SQL-запросов — даёт разницу в единицы процентов или в пределах шума. Точные цифры зависят от вашего кода: измеряйте на своём приложении, а не переносите чужой результат.
| Тип нагрузки | Что делает код | Ожидаемый эффект JIT |
|---|---|---|
| Счётный алгоритм | Арифметика в циклах, без I/O | Кратное ускорение |
| Веб-запрос с БД | ORM, SQL, шаблоны, сеть | В пределах погрешности |
| Обработка изображений на PHP | Пиксельные операции в циклах | Ощутимое ускорение |
| API-прокси | Ждёт ответа внешнего сервиса | Нет эффекта |
Как включить и что означают параметры
JIT — часть OPcache, отдельного расширения ставить не нужно. Настройка идёт через php.ini. OPcache должен быть уже включён, иначе JIT не заработает.
; php.ini, PHP 8.0-8.3
; OPcache обязателен для JIT
opcache.enable=1
opcache.enable_cli=1
; Буфер под машинный код JIT.
; Это отдельная память, помимо opcache.memory_consumption.
; 0 или пусто = JIT выключен, даже если opcache.jit задан.
opcache.jit_buffer_size=100M
; Режим JIT. 1255 (tracing) - рекомендованный старт.
; tracing профилирует горячие участки и компилирует их.
opcache.jit=tracingПроверить, что JIT реально активен, можно из CLI:
# PHP 8.x
php -i | grep -i jit
# Смотрите строки opcache.jit и opcache.jit_buffer_size.
# Если buffer_size = 0, JIT не работает, даже если opcache.jit=tracing.tracing vs function. В PHP два основных подхода к JIT: function компилирует функции целиком, tracing — только горячие трассы исполнения, выявленные профилированием. Для большинства случаев рекомендуют tracing (значение 1255). Точную семантику цифрового кода режима сверяйте с документацией вашей версии PHP — она детально описана в разделе про OPcache.
Подводные камни в проде
Включить JIT одной строкой легко. Проблемы начинаются в эксплуатации.
- jit_buffer_size — это отдельная память. Она не входит в
opcache.memory_consumption. Слишком большой буфер на слабом сервере — лишний расход RAM без отдачи, если код не счётный. - PHP-FPM и короткие воркеры. JIT профилирует во время работы процесса. Если воркеры быстро перезапускаются или обрабатывают мало запросов, компиляция не успевает окупиться.
- Отладка усложняется. При падении в JIT-коде стек-трейс может быть менее очевидным. Для диагностики иногда приходится временно отключать JIT, чтобы понять, воспроизводится ли проблема без него.
- Preloading. JIT сочетается с
opcache.preload, но это отдельная тема настройки, здесь её не разворачиваем.
Как проверить, нужен ли JIT именно вам
- Снимите профиль реального запроса под нагрузкой — Xdebug profiler, Blackfire или Tideways. Посмотрите долю CPU-времени в самом PHP против ожидания I/O и БД.
- Если больше половины времени уходит на ожидание базы, сети и файлов — JIT почти ничего не даст. Занимайтесь запросами к БД и кешированием.
- Если есть тяжёлые счётные участки в чистом PHP — включите JIT в
tracingи замерьте до/после на одинаковой нагрузке (одно железо, тот же объём данных, та же параллельность). - Сравнивайте медиану и перцентили времени ответа, а не одно значение: разница в единицы процентов легко тонет в шуме.
Что делать дальше
Если у вас типичное веб-приложение с базой — сначала выжмите то, что даёт реальный эффект: индексы и план запросов в БД, кеширование ответов и объектов, OPcache без JIT. JIT оставьте на потом и включайте только под замер. Если у вас счётная нагрузка — обработка медиа, аналитика, генерация — включите tracing, подберите jit_buffer_size и померьте на своих данных. Дальше смотрите за потреблением памяти воркерами FPM и за долей CPU в профиле: именно она подскажет, есть ли смысл держать JIT включённым.
Редактор изображений: Убрать лишнее, заменить фон, добавить объект, расширить кадр — на вашем изображении.
Спросить за 20 ₽Источники: PHP Manual — OPcache configuration (opcache.jit), PHP RFC: JIT
Частые вопросы
У меня Laravel и MySQL, включил JIT — время ответа не изменилось. Это нормально?
А если у меня PHP 8.0, а не 8.2 — приёмы те же?
Я включил opcache.jit=tracing, но ускорения нет вообще. Что проверить?
Может ли JIT замедлить приложение?
Нужно ли включать opcache.enable_cli для веб-сайта?
Как понять, стоит ли вообще возиться с JIT?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.