浪白的博客の小站
首页项目归档照片墙音乐灵境说说杂谈友链关于
封面

PHP 8 的 JIT 我实测了一下,结论有点意外

写作时间:2026-04-14 20:50:00
# PHP
# 性能
# 实测

PHP 8.0 引入 JIT 的时候,各种文章标题都很激动。我拖了很久没试,上个月终于在一个真实项目上做了对比测试,记录一下。

测试环境

  • PHP 8.2.15(Opcache 开启)
  • 项目是个中等规模的 Web 应用,Laravel 10
  • 压测工具是 wrk,4 线程 100 连接,跑 60 秒
  • 机器是 4 核 8G 的云主机,PHP-FPM 静态 20 个子进程

对比三组配置:

组 Opcache JIT
A 开 关
B 开 tracing,jit_buffer_size=64M
C 开 function,jit_buffer_size=64M

结果

测了三个接口:一个纯计算的(生成报表数据)、一个典型 CRUD(查数据库返回 JSON)、一个渲染页面的。

接口类型 A(无 JIT) B(tracing) C(function)
纯计算 1250 req/s 1380 req/s 1290 req/s
CRUD 3400 req/s 3410 req/s 3400 req/s
页面渲染 890 req/s 895 req/s 890 req/s

纯计算那个提升约 10%,其它两个基本没差别(在误差范围内)。

为什么和宣传的差这么多

看了一些资料,原因大致清楚:

JIT 只优化"热点"代码。 它需要同一段代码被执行足够多次才编译。而 Web 请求的特点是:一次请求执行几千行代码,每行只执行一次。跑到 JIT 阈值之前,请求已经结束了。

PHP 的瓶颈通常不在 CPU。 CRUD 接口的时间基本花在:网络往返、数据库查询、序列化。JIT 优化不到这些。

I/O 等待期间 CPU 是闲的。 一个请求等数据库 20ms,这 20ms 里 JIT 编译得再快也没用。

框架的开销不在计算上。 Laravel 启动、路由匹配、容器解析,这些是大量的函数调用和小对象创建,JIT 能帮一点但有限。

什么时候 JIT 有用

从我看到的资料和自己的测试,比较确定的场景:

1. 长时间运行的计算任务。 比如图像处理库、数学运算、模板编译。有个知名的例子是 php-cs-fixer 这类工具,开了 JIT 能快 20%~30%。

2. 常驻内存的运行模式。 比如 RoadRunner、Swoole 这种,进程不重启,热点代码能被充分 JIT。这种情况下收益明显得多。

3. 复杂正则和字符串处理。 有测试显示这类操作提升比较可观。

4. 单元测试跑得快一点。 这个是真能感觉到的,因为测试会反复执行同样的代码路径。

一个反直觉的发现

开 JIT 之后内存占用涨了。

A 组每个 FPM 进程大概 32MB,B 组涨到 40MB 左右,多了 jit_buffer_size 的一部分常驻。20 个进程就是多 160MB。

在我们那台 8G 机器上无所谓,但如果是在内存紧张的容器里,这个开销要算进去。

配置细节

如果要用,配置大概是:

; tracing 模式,最通用
opcache.jit=tracing
opcache.jit_buffer_size=64M

; function 模式,只做函数级优化,编译开销小
; opcache.jit=function
; opcache.jit_buffer_size=32M

opcache.jit 也可以写四位数组合,比如 1205,分别控制优化级别、寄存器分配、触发方式、优化策略。但说实话我没仔细研究过这些,默认的 tracing 和 function 够用。

几个注意点:

  • jit_buffer_size=0 才是完全关闭,不写这行默认也是 0
  • CLI 和 FPM 的配置要分别设(php.ini 和 php-fpm.conf 里的 php_admin_value)
  • 改完要重启 FPM,reload 不生效

我的结论

对大多数 Web 项目,JIT 的收益不值得专门去调。

我最后还是开着(tracing 模式),因为纯计算那个接口有 10% 提升,而且内存够用。但如果有人问我"要不要为 JIT 升级 PHP",我会说:升级 PHP 版本本身(8.0 到 8.2 的性能改进)比 JIT 重要得多。

PHP 8.0 到 8.2 之间的性能提升主要来自:

  • 更高效的对象模型
  • readonly 属性减少了防御性拷贝
  • 枚举比常量快
  • 一些内部函数用 C 重写

这些是普适的提升,不挑场景。

如果真的要优化 PHP 性能

按收益排序,我的建议是:

1. 先看慢查询。 加个 slow log,八成能找到问题。这个收益通常是数倍,不是百分之几。

2. 检查 Opcache 配置对不对。 opcache.validate_timestamps=0 在生产环境应该打开(配合部署时重启 FPM),能省掉每次 stat 文件的开销。opcache.memory_consumption 要够大,不然缓存命中率低。这个经常被忽略。

3. 看有没有 N+1 查询。 Laravel 里 with() 忘了写,或者循环里查数据库,这个太常见了。

4. 考虑加缓存。 Redis 缓存热点数据,收益通常比 JIT 高一个数量级。

5. 最后才考虑 JIT。

顺序很重要。我见过花两周调 JIT 参数,结果发现有个接口本来应该 20ms 返回却要 800ms——因为少了个索引。

avatar

浪白

邪恶的浪白

RECOMMENDED

Composer 用了这么多年,几个我认为值得坚持的习惯

2026-04-27 19:15:00

context 传参这件事,我踩过的三个坑

2026-05-06 20:05:00

Go 的 error 处理,用久了反而觉得还行

2026-04-19 22:15:00

Table of Contents