Hyperf内存持续升高基本可断定为内存泄漏,需用swoole_tracker捕获malloc/free不匹配,结合ps aux观察RSS线性上涨趋势,重点排查dispatch_mode配置、Context未清理、静态变量累积及C扩展内存持有问题。
Hyperf项目部署后内存持续升高,基本可以断定是内存泄漏,而不是“偶发卡顿”或“瞬时高峰”。关键不是猜原因,而是快速确认泄漏是否存在、定位到具体模块——
是目前最直接有效的工具,它能捕获 C 层 malloc/free 不匹配,而这是
和 PHP 日志完全看不到的盲区。
看 RSS,别信 memory_get_usage()
协程常驻进程下,
只反映 Zend 堆内存,漏掉了协程栈、Redis/PDO 扩展持有的 C 层内存、Swoole 自身 malloc 分配。你看到“用了 12MB”,实际
显示 RSS 已涨到 320MB——差额就是泄漏本体。
用
每 30 秒观察,RSS 是否线性上涨
在请求末尾加
,等 5 秒再看 RSS 是否回落;不回落,说明存在强引用未断(比如闭包捕获大对象、静态变量存了 Request 实例)
不要依赖日志里打印的
值做判断,它对泄漏排查几乎无效
swoole
_tracker 配置必须关掉 tracker.enable
和
不能同时开启,否则 hook 失效。线上复现阶段必须关闭总开关,只启用 malloc hook 和 memcheck。
正确配置片段:
、
、
采样率别设 100:调试时用
,上线环境严禁全量采样,否则性能暴跌
泄漏日志默认输出到
,典型行如
,直接定位到 C 文件行号
Worker0 内存独高?先查 dispatch_mode
如果只有 Worker0 RSS 持续飙升,其他 Worker 正常,大概率不是代码泄漏,而是配置误配导致流量全部打到 Worker0。
Swoole 6.1.1
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
下载
检查
:值为
(即
)时,所有请求会发往 Worker0,造成单点内存暴涨
应改为
(
)或
(
),让负载均衡分发
加日志时务必带上
,避免多 Worker 日志混杂失焦,例如:
协程退出 ≠ 内存释放,Context 和静态变量是重灾区
协程结束时,栈内存自动回收,但堆内存里的 Context 数据、静态属性、未 close 的协程句柄仍长期驻留。
后没配
清理,协程退出后数据还在
类中定义
,每次请求都
,越积越多
自定义进程中用
启协程,却忘了
收尾
验证方式:在关键节点插入
,但仅作辅助,最终以 RSS 变化为准
真正难排查的泄漏,往往藏在 C 扩展调用链里(比如 Redis::hGetAll 返回大数组后被静态变量持有),
是唯一能穿透 PHP 层直达 malloc 调用栈的工具。别在 Hyperf 日志里翻来覆去找“谁没 unset”,要去看协程真实生命周期和内存分配路径——那才是泄漏发生的现场。
swoole_trackermemory_get_usage()memory_get_usage(true)ps auxps aux --sort=-rss | head -5gc_collect_cycles(); gc_mem_caches();memory_get_usage()tracker.enabletracker.enable_malloc_hooktracker.enable=0tracker.enable_malloc_hook=1tracker.enable_memcheck=1tracker.sampling_rate=10/tmp/swoole_tracker.log[leak] addr=0x7f8b4c0a1234 size=16384 at ext/redis/redis.c:1234server.settings.dispatch_mode2SWOOLE_DISPATCH_QUEUE1SWOOLE_DISPATCH_FDMOD3SWOOLE_DISPATCH_IPMODposix_getpid()$this->logger->info('SQL executed', ['pid' => posix_getpid(), 'sql' => $sql])Context::set('big_data', $hugeArray)deferpublic static $cache = []$cache[] = $itemCoroutine::create()Coroutine::close()echo memory_get_usage(true), "\n";swoole_tracker