Webman中static缓存无限增长是内存泄漏的典型信号,如php start.php status显示内存从64M涨至383M且不回落,说明存在长生命周期引用未清理,需主动释放static数组、闭包捕获对象及C扩展资源。

Webman 中 static 缓存无限增长是内存泄漏的典型信号
看到 php start.php status 显示内存从 64M 涨到 383M 且不回落,基本可以断定存在长生命周期引用未清理。Webman 是常驻进程框架,static 数组一旦被写入,其生命周期就与 worker 进程等长——业务每来一次请求就塞一条数据进去,又不主动清理,self::$cache 就成了内存黑洞。
常见错误模式:
- 在中间件或控制器里直接往
self::$instances写入大对象(如new HeavyService()) - 用字符串 key 缓存配置、用户会话或查询结果,但没配套
clear()或 TTL 机制 - 把 Swoole 的
$server->connections或$fd当作缓存键长期持有,而连接已断开但引用还在
这类问题不会报错,也不会立刻崩溃,但压测 30 秒后 RSS 翻五倍就是最直接的证据。
协程上下文里闭包捕获 $this 导致服务容器被钉住
Webman 默认启用协程,很多开发者习惯在路由回调里写匿名函数,比如:
立即学习“PHP免费学习笔记(深入)”;
$route->get('/api', function () {
$user = User::find(123);
return $user->toArray();
});
表面看没问题,但如果这个闭包是在某个类方法内定义的,并且内部访问了 $this->container 或 $this->db,那整个服务容器实例就会被闭包强引用,无法被 GC 回收。
更隐蔽的是事件监听场景:
-
Event::on('order.created', function () use ($this) { ... })——use ($this)直接把当前对象锁死 - WebSocket
onMessage回调中 new 一个带依赖注入的处理器,但没显式销毁 - 定时器回调(
Timer::tick())持续运行,每次回调都新建对象并存进静态数组
这类泄漏的特点是:单次请求结束时 memory_get_usage() 下降,但 ps aux 看 RSS 不降——说明 PHP 层对象被回收了,但底层 C 扩展或静态结构仍持有着引用。
必须显式释放的三类资源,PHP GC 完全不管
Webman 长连接场景下,以下资源不手动处理,就等于给内存加锁:
-
imagedestroy($image):GD 图像资源分配在 C 堆上,unset()或对象析构都不触发释放 -
$redis->close()或$redis = null:Swoole Redis 客户端若复用连接池,未 close 会导致连接句柄和缓冲区持续累积 -
$spreadsheet->disconnectWorksheets():PhpSpreadsheet 的 worksheet ↔ workbook 双向引用必须手动断开,否则整张表内存永远不释放
特别注意:Swoole 的 Coroutine\Channel、Coroutine\WaitGroup 和 Timer 实例也属于此类。它们不是普通 PHP 对象,底层由 C 结构管理,unset() 后仍可能继续占用内存,必须调用 close() 或 clear() 方法。
诊断时别只盯 memory_get_usage(),RSS 才是真相
memory_get_usage() 只反映 Zend VM 分配的内存,对扩展层、系统堆、共享内存完全不可见。你看到它下降了,不代表进程 RSS 下降。
真实排查步骤:
- 用
ps aux --sort=-%mem | head -n 5每 10 秒抓一次 RSS,确认是否持续上涨 - 在关键逻辑后加
gc_collect_cycles(); gc_mem_caches();,再看 RSS 是否回落;不回落=强引用还活着 - 对可疑对象执行
debug_zval_dump($obj),重点看refcount__gc是否 >1,is_ref__gc是否为 1 - CLI 下跑脚本时加
ZEND_MM_DEBUG=1 php script.php,观察emalloc/efree是否成对出现
最容易被忽略的是:Webman 的 onWorkerStart 里初始化的静态资源(如 Redis 实例、日志 Handler),它们在 worker 生命周期内只初始化一次,但若内部缓存了大量数据,就再也没有机会清空——除非你主动在 onWorkerStop 里做清理。



















