Webman内存泄漏需切断static数组、闭包use、事件监听器三类强引用链;真泄漏表现为RSS持续上涨且GC后不回落,非memory_get_usage()可判别。

Webman内存溢出不是配大memory_limit就能解决的,真泄漏时调高限制只会延缓崩溃——核心得切断static数组、闭包use、事件监听器这三类强引用链。
怎么确认是真内存泄漏而不是假性溢出
别信memory_get_usage(),它只看PHP堆,不反映操作系统真实占用。Webman长驻进程里,真正危险的是RSS(常驻集大小)持续上涨且GC后不回落。
- 用
ps aux --sort=-%mem | head -10</li> <li>压测前记下RSS(比如42MB),发起100次相同请求后立刻执行<code>kill -USR2 {pid}触发reload,再查RSS:如果卡在65MB不回落,就是泄漏;回落到45MB左右,大概率只是GC滞后或缓存合理增长 - 关掉xdebug:
php -d zend_extension= -f start.php跑一遍,排除调试扩展干扰 - 检查有没有大文件临时加载、
var_dump()残留、未关闭的fopen()句柄
static数组无限追加是最常见的泄漏源头
Webman Worker进程不死,static $cache = []就永远活着。每次请求[]=塞一条,没清理机制,几万次后就是几百MB黑洞。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 全局搜索
static $、protected static $cache、self::$log等模式,重点盯app/Middleware/和app/Listener/目录 - 错误写法:
self::$data[] = ['uri' => $request->uri(), 'body' => $request->raw()];——$request->raw()可能带几MB原始数据 - 正确做法:改用带容量上限的循环队列,例如
count(self::$cache) > 1000 && array_shift(self::$cache); array_push(self::$cache, $item); - 更稳妥方案:直接删掉裸
static数组,换Webman\Support\Cache::remember()或Redis,强制设TTL
闭包和事件监听器偷偷钉住Request/Response对象
看起来只是读个字段,但use ($request)会让整个$request实例无法被GC回收——它内部持有着上传文件、原始body、解析后的JSON等大块内存。
- 排查所有
Event::on()、Timer::tick()、WebSocketonMessage里的匿名函数 - 特别警惕
use ($this):一旦闭包捕获了当前类实例,整个服务容器、DB连接、日志处理器都跟着锁死 - 定时器回调中避免新建对象并存进静态数组,改成每次用完就
unset($item)或用WeakMap(PHP 8.0+)替代 - 临时验证:在中间件末尾加
gc_collect_cycles(); gc_mem_caches();,再看RSS是否下降——不降,说明有强引用钉着
为什么重启Worker进程后内存还是不释放
因为某些C扩展资源(如Swoole连接、MySQL协程句柄、第三方SDK的HTTP client)没显式销毁,或者OPcache在CLI模式下开了opcache.enable_cli=1,导致编译后的opcode永久驻留。
- 检查
config/database.php里MySQL连接池是否配置了pool.max_connections,并确认每次使用后都调用了$pool->put($conn) - 在
Worker::onWorkerStop里手动调用SDK的close()或disconnect()方法(EasyWeChat、Alibaba Cloud SDK等文档一般会注明) - 运行
php --ri opcache,确认opcache.enable_cli是Off——CLI模式下开它,内存根本不会归还 - 监控进程数是否异常:如果
php start.php status显示worker数量远超配置的$worker->count,可能是子进程没退出干净,需检查信号处理逻辑
最易被忽略的一点:泄漏往往不在业务代码里,而在你信任的“辅助工具”中——Monolog的FingersCrossedHandler缓存未触发日志、ORM模型事件监听器互相持有、甚至$_ENV里塞了大数组,都可能成为内存黑洞。排查时先停掉所有非核心中间件和监听器,再逐个开,比盲猜高效得多。

















