Webman进程内存持续上涨且不回落,说明存在长生命周期引用未清理;典型表现是static数组无限写入、闭包捕获$this锁死服务容器、第三方SDK资源未手动释放,需主动清理、改用WeakMap或带TTL的Cache。

Webman 进程内存持续上涨且不回落,基本可以断定存在长生命周期引用未清理——不是 PHP GC 失效,而是你写的代码把对象“钉”在了内存里。
static 数组无限写入却不清理
Webman 是常驻进程框架,self::$cache、static $data = [] 这类结构的生命周期与 worker 进程等长。每次请求都往里面 []= 或 $arr[$key] = $value,又没配套 unset() 或清空逻辑,就是最典型的内存黑洞。
- 搜索全部
static $声明,尤其带数组初始化的; - 检查所有写入点:路由回调、中间件、事件监听器里是否无条件追加;
- 缓存场景必须加 TTL 和容量限制,直接换用
Webman\Support\Cache,别手写裸数组; - 若确需静态存储,写入后明确标记过期时间,并在
onWorkerStop或定时器中批量清理。
闭包捕获 $this 导致服务容器被锁死
协程环境下,匿名函数里访问 $this->container 或 $this->db,会让整个服务容器实例被强引用,GC 无法回收。现象是 memory_get_usage() 看似回落,但 ps aux 的 RSS 持续上涨。
- 重点排查
onMessage、onConnect、Timer::tick()、事件监听(如Event::on('xxx', function() use ($this) { ... })); - 避免
use ($this),改用传参方式传递必要对象,或提取为独立函数; - 必须缓存连接上下文时,优先用
WeakMap(PHP 8.0+):private static $contextMap = new WeakMap();; - 在连接关闭或任务结束回调中显式调用
gc_collect_cycles(),并对比memory_get_peak_usage(true)是否回落。
第三方 SDK 与 C 扩展资源未手动释放
EasyWeChat、Redis 客户端、GD 图像资源等,底层分配在 C 堆上,PHP GC 完全不感知。比如 imagedestroy($image) 必须显式调用,unset() 或析构函数无效。
- 检查所有 SDK 初始化是否放在
onWorkerStart中,而非每次请求重复new; - 确认文档是否要求
close()、disconnect()、destroy(),并在onWorkerStop或onClose中执行; - GD 操作后必须调用
imagedestroy($image),否则图像资源永久驻留; - Redis 连接不要全局单例复用,改用懒加载 + 健康检测:
if (!$this->redis || !$this->redis->isConnected()) { ... }。
真正难排查的泄漏,往往藏在“看起来没问题”的地方:一个没 unset 的 foreach 引用、一个忘了 remove 的事件监听器、一个用字符串 key 缓存却从不淘汰的配置项。RSS 不降,说明 C 层或静态结构还在持有着引用——这时候看 memory_get_usage() 已经没用了。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











