应监控 rss 而非仅 memory_get_usage(),结合 gc_collect_cycles()、weakreference 检测强引用、排查 swoole 5 特有泄漏点(如未关闭资源、静态缓存、定时器残留等),必要时用 meminfo 或 swooletracker 深度定位。

直接看 RSS(常驻内存)是否随时间持续上涨,而不是只盯 memory_get_usage()。Swoole 5 常驻服务的内存问题,90% 不是 PHP 对象没释放,而是强引用未断、资源未销毁、或内存碎片堆积——得用分层手段定位。
盯住真实内存:监控 RSS + 定期 GC
PHP 层的 memory_get_usage() 只反映 Zend 内存管理器分配量,掩盖了 C 扩展、系统堆、内存碎片等真实开销。必须结合操作系统级指标:
- 用
ps aux --sort=-rss | head -20或smem -P php查看 worker 进程 RSS 实际占用,每 30 秒采样一次,画趋势图 - 在每次请求/任务结束后主动调用:
gc_collect_cycles();<br>gc_mem_caches();
前者清理循环引用,后者清空小内存块缓存(解决 PHP 小内存不归还 OS 的碎片问题) - 若 GC 后 RSS 仍不回落,说明有外部强引用钉住了对象(如静态属性、全局数组、事件监听器、闭包捕获 $this)
查谁在持有:用 WeakReference + debug_zval_dump 辅助验证
对可疑对象(比如某个 Service 实例、配置容器、ORM 上下文),加一层弱引用监控:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 创建对象后立即用
WeakReference::create($obj)包裹 - 业务逻辑结束后,检查
$weakRef->get() !== null—— 若仍能取到,说明还有其他变量/静态属性在强引用它 - 配合
debug_zval_dump($obj)看refcount__gc和is_ref__gc,确认是否被意外绑定 - 特别注意闭包:匿名函数若用了
use ($this)或use (&$var),会形成隐式强持
扫常见雷区:Swoole 5 特有高危点
Swoole 5 强化了协程调度和内存保护,但几个典型泄漏点反而更隐蔽:
-
协程内未关闭的资源:PDO 长连接未设
PDO::ATTR_PERSISTENT => false;Redis 客户端复用时未调用close();文件句柄未fclose()或未用defer -
静态缓存无清理机制:类中
private static $cache = [];存了大对象,但没配套clear()方法,随 worker 寿命无限累积 -
定时器/延时任务残留:用
Swoole\Timer::after()或tick()注册回调后,没在业务结束时Swoole\Timer::clear() -
事件监听未解绑:向
Swoole\Event或自定义事件总线注册了监听器,但没在 onWorkerStop 或任务退出时removeListener -
GD / XML / DOM 资源未销毁:
imagedestroy($img)、$dom->clear()、$xpath->registerNamespace()后未清理命名空间缓存
进阶定位:堆快照 + SwooleTracker
当常规手段无法锁定目标,进入深度排查:
- 启用
ZEND_MM_DEBUG=1启动 Swoole(仅限开发环境),观察 emalloc/efree 是否配对 - 装
meminfo扩展,调用meminfo_dump()生成堆快照,对比两次快照间增长最多的类名和实例数 - 使用 SwooleTracker,在关键入口埋点:
Swoole\Tracker::start();<br>// ...业务逻辑...<br>$report = Swoole\Tracker::report();
可精准定位哪段代码新增了最多对象或内存 - Linux 下用
valgrind --tool=memcheck --leak-check=full php your_server.php检测 C 层泄漏(需编译带调试符号的 Swoole)









