opcache内存与memory_limit完全隔离,前者是进程级共享的固定内存池,后者是单请求堆内存上限;容器总内存需≥opcache内存+线程数×平均请求内存,并预留20%缓冲。

OPcache内存不是PHP memory_limit,别混着设
很多人一看到opcache.memory_consumption=256就顺手把memory_limit=256M也设成一样,这是错的。OPcache 内存是 PHP 进程启动时向 OS 单独申请的一块共享内存区域,和每个请求用的堆内存(memory_limit)完全隔离。它不随请求结束释放,而是长期驻留——尤其在 worker 模式下,所有请求共用同一份缓存。
常见错误现象:opcache_get_status()['opcache_statistics']['oom_count'] > 0,说明 OPcache 自身内存不够,频繁踢出旧脚本重编译;但 php -r "echo memory_get_usage();" 显示单请求内存很低,误以为“没压力”。
- OPcache 内存必须独立评估:主要看项目 PHP 文件总数、类数量、是否含大量注解(
opcache.save_comments=1会显著增耗) - worker 模式下,
opcache.memory_consumption× 线程数 ≠ 总内存占用,因为这块内存是进程级共享的,不是每个线程一份 - 容器内存限制(如
mem_limit: 512m)必须 ≥ OPcache 内存 + 所有线程的平均堆内存 × 并发峰值,建议留 20% 缓冲
怎么算够用:按文件数和框架类型反推
别猜,直接查项目真实文件规模。Composer 自动加载 + 框架生成类(Laravel 的 bootstrap/cache/*.php、Symfony 的 var/cache/)才是大头。执行:find ./app ./src ./vendor -name "*.php" | wc -l,再加 find ./var/cache ./bootstrap/cache -name "*.php" | wc -l(Symfony/Laravel 场景)。
参考值(已验证于 FrankenPHP v1.2+):
- 纯 WordPress(无插件):~8k 文件 →
opcache.max_accelerated_files=12000+opcache.memory_consumption=256 - Laravel 中型项目(含 Scout、Horizon):~15k 文件 →
opcache.max_accelerated_files=20000+opcache.memory_consumption=384 - Symfony + Mercure + API Platform:~22k 文件 →
opcache.max_accelerated_files=30000+opcache.memory_consumption=512 - 注意:
opcache.max_accelerated_files必须 ≥ 实际文件数,否则多余文件永远进不了缓存,opcache_get_status()['opcache_statistics']['max_cached_keys']会卡在设定值不动
调完必须验证:盯住 oom_count 和 hit_rate
改完 php.ini 重启 FrankenPHP 后,不能只看 opcache.enabled 是 On 就完事。上线跑 10–15 分钟真实流量,立刻检查两个硬指标:
-
opcache_get_status()['opcache_statistics']['oom_count'] === 0:大于 0 就得加opcache.memory_consumption,不是“可能不够”,是“已经不够” -
opcache_get_status()['opcache_statistics']['hit_rate'] >= 0.95:低于 0.9 表明缓存命中差,大概率是opcache.max_accelerated_files设小了,或opcache.validate_timestamps=0但没调opcache_reset() - 避免只测首页:用 curl 或 k6 访问几个典型路由(如 Laravel 的
/api/users、WordPress 的/wp-json/wp/v2/posts),触发不同文件路径
多个应用共用 FrankenPHP 容器?别分内存,直接拆
FrankenPHP 多应用共存时,opcache.memory_consumption 不是“给 A 应用 256MB、B 应用 256MB”,而是所有应用共享同一块 OPcache 内存池。Laravel 的代理类、WordPress 的插件文件、自定义工具库全挤在一起,极易触发 oom_restarts > 0 和 RSS 内存暴涨。
真实踩坑案例:两个中型 Laravel 应用共用一个 FrankenPHP 容器,各自设 memory_limit=256M,opcache.memory_consumption=384,结果容器 RSS 达 1.4GB,dmesg 显示被 OOM Killer 杀掉。
- 唯一安全做法:每个应用独占一个 FrankenPHP 容器(或至少一个独立进程),用反向代理(Caddy/Nginx)做路由分发
- 如果必须共存,至少把
opcache.memory_consumption设到单个应用需求的 2.5 倍以上,并持续监控oom_count和opcache_get_status()['interned_strings_usage']['buffer_size']是否接近上限 - 别信“我只改了 config,没动代码,所以不用清缓存”——Symfony 的 YAML 配置解析、Laravel 的
config/*PHP 文件都会进 OPcache,部署后必须opcache_reset()
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











