PHP-FPM 内存涨上去下不来,很多人第一反应是加内存,其实多数情况是配置或代码把内存钉住了。最近排查一个长驻 Worker 内存缓慢上涨的服务,按下面顺序定位,比盲目重启管用。
第一,先分清是 OPcache 还是业务内存。OPcache 占用的共享内存是预期内的,重启后会重新增长到上限然后平稳;业务内存泄漏是单进程 RSS 持续爬升。看 opcache 状态面板确认缓存命中率和内存占用,再看单个 Worker 的 RSS 趋势,两者混在一起查只会越查越乱。
第二,查长驻进程的静态持有。常驻进程里 static 变量、单例缓存、事件监听器不释放,请求结束也不会回收。重点看那些“为了性能”做的进程级缓存:有没有上限、有没有过期、异常分支会不会跳过清理。没有上限的缓存就是披着优化外衣的泄漏。
第三,查循环引用和大对象。PHP 的引用计数处理不了循环引用,虽然有 GC 兜底,但 GC 阈值默认较高,大对象循环引用多了,内存会在 GC 触发前涨很高。怀疑时开 gc_status 看收集次数和根缓冲区,必要时在长任务里手动 gc_collect_cycles 验证。
第四,给 Worker 设合理的重启策略。pm.max_requests 不是偷懒,是兜底:设一个较大的请求数上限,让 Worker 定期重生,内存基线能回到正常水平。同时把重启间隔和内存基线记下来,下次上涨先对比基线,再决定是查代码还是调配置。
大家在 PHP 长驻进程里,内存基线一般控制在什么水平?有没有查出过静态缓存导致的缓慢泄漏?