必须配置worker重放周期,因为常驻进程内存会持续累积泄漏,即使无代码错误,第三方sdk也可能导致内存耗尽;需按请求数或运行时间触发平滑重启,并配合内存管理措施。

Webman 内存缓慢增长不是 bug,是常驻进程的必然现象;但不设重放周期(即 Worker 进程软重启策略),就等于放任内存泄漏累积,最终触发 Allowed memory size of XXX bytes exhausted。
为什么必须配 Worker 重放周期
Worker 进程长期运行时,静态变量、闭包引用、未释放的 SDK 资源、缓存数组等不会自动清空。PHP GC 在循环引用或弱引用链断裂不及时的场景下基本失效。哪怕每次请求只多占几 KB,百万请求后就是 GB 级别——而 memory_get_usage() 看似平稳,memory_get_peak_usage(true) 却持续上扬,就是典型信号。
- 不重启 ≠ 不泄漏:即使没写错代码,第三方 SDK(如 EasyWeChat、阿里云 OSS)内部持有的定时器、连接池、回调闭包也会悄悄吃内存
- 硬 kill 进程会丢连接:直接
kill -9导致正在处理的 WebSocket 消息中断、HTTP 请求响应失败 - 重放周期 ≠ 频繁重启:目标是“可控衰减”,不是“每分钟拉起新进程”
如何配置 soft-restart 周期(推荐方案)
Webman 本身不提供 max_requests 或 reload_interval 这类 Nginx 式参数,需手动在 start.php 中基于请求数或运行时间触发平滑重启。
- 按请求数重启:在
Worker::onRequest中用静态计数器,达到阈值后调用Worker::stopAll(0),由主进程自动拉起新 Worker - 按运行时间重启:启动时记录
$_SERVER['REQUEST_TIME_FLOAT'],在onWorkerStart启动一个Timer::add(60, ...)定时检查time() - $start_time > 3600(如 1 小时),满足则Worker::stopAll(0) - 必须配合
Worker::$daemonize = true和Worker::$logFile,否则stopAll()会直接退出整个服务 - 避免在
onMessage或中间件里调用stopAll():WebSocket 连接可能正收发数据,应改用Connection::close()先清理连接再停 Worker
容易被忽略的三个关键点
重放周期只是兜底手段,不是替代内存管理的银弹。以下三点不做,重启也白搭:
-
static::$cache必须带容量上限:用array_shift() + array_push()维护滚动队列,禁止无条件$cache[] = $item - 所有
Timer::add()必须配对Timer::del($id),尤其在onClose或状态变更时——漏删一个,就锁死整个对象生命周期 - Redis/MySQL 客户端实例不能全局 new 一次复用到底:应封装为懒加载属性,在每次使用前检查
$this->redis->isConnected(),断连则unset($this->redis)
真正难的不是设个定时器,而是确认每个 static、每个闭包、每个 SDK 实例,都在它该结束的时候被真正切断了引用链。重放周期只是给失控留一条退路,不是默认开启的保险丝。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











