PHP 8.1 开启 JIT 后崩溃主因是 opcache.preload 与 JIT tracing 模式(如1255)冲突,导致类加载阶段符号表绑定缺失、autoload 失效及 opcode 重定义错误;必须禁用 opcache.preload 并重启进程,且需验证其实际未被镜像或平台默认启用。

PHP 8.1 开启 JIT 后崩溃,大概率不是 JIT 本身 bug,而是 opcache.preload 与 JIT 的 opcode 缓存策略在类加载阶段发生冲突,尤其在 Composer autoloader 初始化时触发 Class 'Composer\Autoload\ClassLoader' not found —— 这个错误背后是 JIT 跳过了 preload 阶段本该注册的类映射入口。
opcache.preload 和 JIT 在 PHP 8.1 中根本不能共存
PHP 8.1–8.2 的 JIT tracing 模式(如 opcache.jit=1255)会绕过部分 opcache 的 preload 初始化逻辑,导致 vendor/autoload.php 中的静态初始化块未被执行。这不是 autoload 机制失效,而是 Zend VM 在 JIT 编译路径中漏掉了 preload 预注册的符号表绑定。
-
opcache.preload必须完全禁用:在 php.ini 中设为opcache.preload=(空值)或直接注释掉 - 确认 preload 文件未被任何其他配置间接加载(例如通过
opcache.preload_user或容器启动脚本) - 重启 PHP-FPM 或 CLI 进程后,用
php -i | grep preload验证输出为空
崩溃前常伴随 opcode 重定义错误
典型现象是执行 composer dump-autoload --optimize 后,JIT 在重编译时重复加载 vendor/composer/autoload_classmap.php 中的类定义,触发 Fatal error: Cannot declare class XXX, because the name is already in use。这是因为 JIT 对静态 classmap 的缓存粒度和 opcache 的文件级缓存不一致,导致同一类被两次解析进内存。
- 开发环境避免使用
--optimize:它生成的autoload_classmap.php是静态快照,与 JIT 动态编译节奏天然冲突 - 生产部署若必须 classmap,先临时关闭 JIT(
opcache.jit=0),执行 dump,再恢复 JIT 配置 - 更推荐改用
composer dump-autoload --apcu(需启用apcu.so),APCu 类映射由用户缓存管理,不依赖文件读取,与 JIT 共存性好
如何定位具体是哪个 opcode 触发崩溃
JIT 崩溃往往发生在某个函数首次被判定为“热函数”并尝试编译时。用 opcache.jit_debug=1 可捕获 JIT 编译日志,但需配合 opcache.log_verbosity_level=4 才能看到 opcode 级别细节。
立即学习“PHP免费学习笔记(深入)”;
- 运行命令:
php -d opcache.jit=1255 -d opcache.jit_debug=1 -d opcache.log_verbosity_level=4 -r "require 'vendor/autoload.php'; new \Monolog\Logger('test');" - 观察输出中最后几行是否出现
ZEND_DECLARE_CLASS、ZEND_FETCH_CLASS或ZEND_INCLUDE_OR_EVAL相关的编译失败提示 - 若日志末尾卡在某个
ZEND_INIT_METHOD_CALL,说明崩溃点极可能在该方法所在类的 autoload 加载环节
真正容易被忽略的是:即使你没显式配置 opcache.preload,某些 Docker 基础镜像或云平台 PHP 运行时会默认启用它(比如某些阿里云函数计算环境)。务必检查 php -i 输出里 opcache.preload 行的实际值,而不是只看 php.ini 文件内容。



















