OPcache 在 Symfony 6 中需同时满足 PHP 配置、Symfony 编译适配与部署协同三条件:须分别启用 FPM 和 CLI 的 OPcache(含 opcache.enable_cli=1),调优 memory_consumption、max_accelerated_files 等参数,手动配置 preload.php 并设 preload_user,部署后必须 reload php*-fpm 才能清空并重建 OPcache。

OPcache 在 Symfony 6 中不是“配出来就生效”的功能,而是必须同时满足 PHP 层配置、Symfony 编译逻辑适配、部署流程协同三个条件,缺一不可。单独改 php.ini 或只跑 cache:clear 都可能白忙活。
确认 FPM 和 CLI 的 OPcache 是否真正启用
Symfony 6 的缓存预热、容器编译(如 cache:clear)走 CLI,而实际请求走 FPM —— 这两者用的是完全独立的 PHP 配置。常见错误是只在 FPM 的 php.ini 里开了 opcache.enable=1,但 CLI 没开,导致 preload.php 生成失败或类预加载不生效。
- 查 CLI 配置路径:
php --ini,然后检查该php.ini是否含opcache.enable=1和opcache.enable_cli=1 - 查 FPM 配置路径:在浏览器访问
phpinfo()页面,看「Loaded Configuration File」指向哪,再打开对应文件确认opcache.enable=1 - FPM 改完后必须执行
sudo systemctl reload php*-fpm(不是restart),否则配置不加载 - CLI 不需要长期开启 OPcache,但 Symfony 构建阶段(如
composer install、cache:clear)需它参与预加载,所以opcache.enable_cli=1是必要项
配置关键参数避免缓存抖动和内存溢出
默认 OPcache 参数对 Symfony 6 这类大项目太保守,opcache.max_accelerated_files 设小了会频繁踢出缓存,opcache.memory_consumption 不够则触发 oom_restarts,反而拖慢响应。
-
opcache.memory_consumption=256(单位 MB):中小项目可设 128,但 Symfony 6 + Doctrine + Twig + Bundles 轻松超千个类,建议起步 256,压测后看opcache_get_status()['memory_usage']['used_memory']再调 -
opcache.max_accelerated_files=20000:必须设为质数(如 19997、20011),避免哈希冲突;低于项目真实 PHP 文件数(find src/ -name "*.php" | wc -l)会导致部分文件无法进缓存 -
opcache.validate_timestamps=0:仅限生产环境;开发时必须为1,否则改了Controller.php刷新页面还是旧逻辑 -
opcache.revalidate_freq=2:开发时配合validate_timestamps=1,每 2 秒检查一次文件变更,平衡效率与热更新可见性
启用 Symfony 容器预加载(preload.php)
Symfony 6 默认生成 config/preload.php,但它不会自动被 OPcache 加载——你得手动告诉 PHP 哪个文件要预加载。
- 确保
composer recipes:install symfony/framework-bundle --force -v已运行,生成了config/preload.php - 在 FPM 的
php.ini中添加:opcache.preload=/path/to/your/project/config/preload.php - 必须指定
opcache.preload_user=www-data(或你的 Web 服务器用户),否则因权限问题加载失败,日志里只报“failed to open stream” -
preload.php里用container.preload标签标记的服务类才会被加载;没标的话即使在容器里定义了,也不会进预加载列表
部署时清空并重载 OPcache 的正确姿势
改代码后光 cache:clear 不够,OPcache 里的旧字节码还在内存里。FPM worker 进程不共享 OPcache,所以不能靠 CLI 执行 opcache_reset() 清掉 Web 请求的缓存。
- 最稳妥:部署后执行
sudo systemctl reload php*-fpm,所有 worker 重启,OPcache 自动清空重建 - 次选:写一个 Web 可访问的
opcache-reset.php(含opcache_reset()),用 curl 触发,但需加 IP 白名单或 JWT 验证,否则暴露危险 - 别用
opcache_invalidate()单个文件刷新:Symfony 类多且依赖复杂,局部失效容易引发 autoloader 错误或 class not found - 每次部署后检查
opcache_get_status()['opcache_statistics']['num_cached_scripts']是否明显上升,确认预加载和缓存命中正常
最容易被忽略的是:预加载文件(preload.php)本身如果被修改过(比如你手动删了某行),OPcache 不会自动重新加载它——必须重启 FPM 才能生效。这导致很多“明明改了 preload 却没效果”的问题,根源不在 Symfony,而在 OPcache 的加载机制本身。


















