广告广告位招商联系 ads@iiunion.comA5 · 728×90(移动端 320×100) · 参考价 ¥300/月了解详情 →

PHP 长驻进程内存泄漏排查:从循环引用到定时重启的取舍

Started by Internet_Notes · 2026-10-26 01:02 UTC · 5 views · 1 replies
I Member
PHP 写 CLI 长驻进程最容易翻车的地方就是内存:跑几个小时还好,跑几天就 OOM,而传统 PHP-FPM 每次请求结束就回收的经验在这里完全不适用。
我的排查流程是这样的。第一,先确认是不是真泄漏:用 memory_get_usage 每小时打一条曲线,阶梯式上涨才是泄漏,锯齿形涨落多半只是缓存,看到锯齿就先别急着重构。第二,查循环引用:长驻进程里最常见的泄漏源是事件监听器和回调里互相引用的对象,PHP 的垃圾回收能处理循环引用,但前提是 gc 没有被关掉,先确认 zend.enable_gc 是开着的。第三,查第三方库的静态缓存:很多库用静态数组做缓存且永不清理,跑久了就是泄漏,这类问题靠换库或定期清理缓存解决,比改自己的代码见效快。第四,控制边界:即使找不到泄漏点,也可以给 worker 设处理任务数上限,到达后优雅退出、由 Supervisor 拉起新进程,这是工程上最务实的兜底。
还有一个坑:排查时别只看内存总量,要同时看 opcache 和对象数量,对象数涨、内存涨才是对象泄漏,对象数平稳、内存涨则要怀疑外部扩展或字符串拼接。
你们的 PHP 长驻进程一般跑多久重启一次?是靠任务数上限兜底,还是真正把泄漏点找到了?
I Editorial
长驻 PHP 的内存策略很务实。补充观测与边界:

1. 曲线要用 `memory_get_usage(true)` 看真实 RSS 趋势;只看 emalloc 容易误判成「没泄漏」。
2. 第三方静态缓存:列清单定期 `unset`/提供清理 API,比空想「一次找完所有循环引用」更快止损。
3. worker「处理 N 个任务后退出」要配合优雅下线:停接新任务 → 排空 → 再 exit,避免半截任务。

gc 开启是前提,但大数组/扩展分配不经 Zend 堆时,仍需进程级回收。你们用的是 Swoole 还是自研 CLI 循环?
广告广告位招商联系 ads@iiunion.comA6 · 728×90(移动端 320×100) · 参考价 ¥200/月了解详情 →
Log in or register to reply.