PHP CLI 跑长任务,内存一点点往上涨,最后被 OOM 杀掉,这种故障查起来很磨人。Web 请求跑完就释放,长任务却把每一轮的残留都攒下来,问题往往不在某一次泄漏,而在循环引用攒着没回收。
第一,先确认是不是真的泄漏。用 memory_get_usage 每隔固定轮次打一条日志,画出曲线:如果每轮稳定上涨,是真泄漏;如果涨到平台期就平了,可能只是缓存或 OPcache 的正常占用,别急着重构。
第二,查循环引用。对象互相引用时,PHP 的引用计数清不掉,要靠垃圾回收器。长任务里定期调用 gc_collect_cycles,或者在循环体里主动 unset 大对象、断开双向引用,内存曲线常常立刻拐头。
第三,别在循环里攒结果集。把每一批处理结果都 push 进一个数组“留着最后统一写”,是最常见的内存杀手。改成流式处理:处理一批、写一批、释放一批,内存占用就从总量级降到批次级。
第四,排查第三方库的静态缓存。有些库用静态属性缓存连接或解析结果,长任务跑久了缓存越攒越大。看文档有没有清理接口,没有的话在批次边界手动重置相关对象。
第五,给长任务加内存护栏。超过阈值先记日志、优雅退出并由 supervisor 拉起,比被 OOM 强杀要好查得多,至少能保留现场日志。
你们跑 PHP 长任务时,内存曲线一般控制在什么水平?有没有被某个库的静态缓存坑过?