pm.max_children需实测RSS倒推:用ps aux --sort=-%mem | grep 'php-fpm' | head -n 5取RES中位数,结合可用内存×0.65÷单进程RSS计算,并压测验证;dynamic模式下各参数须按比例配置。

pm.max_children 没有通用公式,硬套“总内存 ÷ 30MB”或“CPU核数 × 2”在 PHP 8.5.5 下大概率导致 OOM 或资源闲置——必须用实测 RSS 倒推,并压测验证。
怎么查单个 php-fpm 进程真实内存占用(不是 VIRT,是 RES)
PHP 8.5.5 开启 opcache.enable=1 和 opcache.preload 后,单进程 RSS 普遍升至 80–120MB,比 8.1 高 10%~15%,ps aux 里看 RES 列才反映真实压力:
- 执行
ps aux --sort=-%mem | grep 'php-fpm' | head -n 5,取RES列中位数(不是最大值,也不是平均值) - 避免用
ps -ylC php-fpm --sort:rss,它在某些内核版本下会把共享内存重复计算,虚高 20%+ - 确认是 worker 进程:排除 master 进程(命令行含
master process),只看php-fpm: pool www类型的行
可用内存怎么算才不翻车
不能直接用 free -h 的 available 值——那是瞬时快照,且未扣除 MySQL/Redis 等常驻服务的实际占用:
- 系统预留 ≥1.5GB:内核、sshd、logrotate、宝塔面板自身等基础服务最低保障
- MySQL/Redis 至少占 1GB:即使配置了
innodb_buffer_pool_size,实际 RSS 往往更高;用ps aux --sort=-%mem | grep -E '(mysql|redis)'实测 - 剩余内存 × 0.65 才是安全上限:留 35% 缓冲防突发 spike,例如总内存 8GB → 可用约 2.8GB → 安全上限 ≈ 1.82GB
pm.max_children = floor(可用内存 ÷ 单进程 RES) 后必须压测
设完就 reload 不等于调优完成,很多团队卡在这步导致上线后 502 爆发:
立即学习“PHP免费学习笔记(深入)”;
- 用
ab -n 5000 -c 200 http://yoursite.com/index.php或wrk -t4 -c200 -d30s http://yoursite.com/模拟真实并发 - 压测中持续运行
free -h,观察available是否稳定 >500MB;跌破说明内存吃紧,需下调pm.max_children - 同时检查
curl http://127.0.0.1/status?full | grep -E "(active processes|max active)":若max active processes长期 ≥90% ofpm.max_children,说明瓶颈真在进程池,而非慢脚本或 DB - 注意
pm.max_requests要同步设为 500–1000:PHP 8.5.5 在高负载下内存泄漏概率仍存在,不设会导致 RES 逐请求缓慢爬升
dynamic 模式下其他参数要按 max_children 梯度配,不能拍脑袋
pm.start_servers、pm.min_spare_servers、pm.max_spare_servers 不是独立参数,它们必须与 pm.max_children 形成比例关系,否则空闲进程抖动剧烈:
-
pm.start_servers=pm.max_children× 0.7(四舍五入取整),例如pm.max_children = 30→ 设为 21 -
pm.min_spare_servers=pm.max_children× 0.5,向下取整,例如 30 → 设为 15 -
pm.max_spare_servers=pm.max_children× 0.9,向下取整,例如 30 → 设为 27 - 这三个值必须满足:
pm.min_spare_servers ≤ pm.start_servers ≤ pm.max_spare_servers ,否则 FPM 启动报错或行为异常
真正容易被忽略的是:opcache.preload 加载的类越多,worker 进程启动时 RSS 就越接近峰值,压测前务必确认 preload 文件已加载完毕(查 phpinfo() 或 opcache_get_status()['preload_statistics']),否则实测 RSS 会偏低,上线后突然爆内存。



















