thinkphp在swoole常驻内存下变“胖”的本质是进程不销毁导致对象、静态变量、单例实例持续累积;典型泄漏点包括static属性、未关闭的数据库连接、闭包回调、重复初始化的日志句柄等,需通过主动归零(如app::clear()、手动close连接、请求级缓存替代静态缓存)来防控。

为什么 Swoole 常驻内存会让 ThinkPHP 变“胖”
ThinkPHP 默认设计是每次 HTTP 请求启动、执行、销毁——所有对象、静态变量、单例实例在请求结束时自动释放。但 Swoole 启动后进程常驻,App 实例、Container、数据库连接、日志句柄、甚至你写的 static $cache = [] 都不会自动清空。久而久之,内存只增不减,memory_get_usage() 一路飙升,最终 OOM。
哪些地方最容易藏泄漏点
不是所有代码都会泄漏,但以下几类特别危险:
-
static属性或全局变量(比如缓存数组、计数器)——下次请求直接复用,越积越多 - 未显式关闭的
think\db\Connection或手动 new 的 PDO 实例——Swoole 不会帮你回收连接资源 - 注册了闭包回调但没清理(如事件监听器、中间件里用
Event::listen()动态注册)——闭包持有了当前上下文引用,导致整个请求栈无法 GC - Log 类被反复调用
Log::init()却没重置——底层Handler实例不断叠加,每个都持有文件句柄或 Socket 连接
怎么安全地在 Swoole 中用 ThinkPHP
核心原则:主动“归零”,而不是依赖销毁。官方 think-swoole 扩展做了部分隔离,但仍有盲区:
- 每次请求开始前,调用
App::clear()清除容器绑定、路由规则、钩子事件 —— 注意它不清理static属性,得自己动手 - 数据库连接必须用
Db::connect()->close()或配置'deploy' => 0禁用读写分离连接池(否则连接数爆炸) - 避免在控制器/服务层写
static $data = [],改用Request::instance()->getCache('key')或 Redis - 日志务必设为按请求生成独立实例:
Log::init(['type' => 'file', 'path' => RUNTIME_PATH . 'log/' . date('Ym/d') . '/']),否则多个请求共用一个 Handler
验证泄漏是否真被堵住
别只看单次请求内存,要压测 + 观察趋势:
- 用
ab -n 1000 -c 10 http://127.0.0.1:9501/模拟并发,每 100 次请求后执行php think swoole:status查看 worker 内存 - 在关键位置加
echo memory_get_usage() . PHP_EOL;,对比第 1 次和第 500 次请求的差值 —— 理想情况应波动不超过 200KB - 注意
gc_collect_cycles()不会立刻生效,Swoole 下建议每 50 次请求后手动触发一次,但别滥用,它本身有开销
最隐蔽的泄漏往往来自第三方扩展或你自己封装的“工具类”,它们悄悄 hold 住了 Request 或 App 实例。只要进程不死,引用链不断,GC 就绕不开。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











