swoole websocket 内存问题主因是 socket_buffer_size、worker_num 和闭包引用:socket_buffer_size 建议设为65536,worker_num 推荐 cpu 核数×1.5,闭包中应只传必要变量并避免捕获 $server 或大体积 $frame->data。

直接说结论:Swoole 高并发 WebSocket 服务的内存问题,80% 出在 socket_buffer_size、worker_num 和未清理的闭包引用上,而不是 PHP 本身或 GC 设置。
socket_buffer_size 调大反而吃光内存?
每个连接默认分配读写缓冲区各 128KB(Linux 下 TCP 默认 rmem/wmem),1 万连接就是 2.5GB 内存——这和你代码里有没有 new 无关,是内核级开销。
- 必须显式设置
socket_buffer_size,建议值:64K(即65536);超过 128K 后吞吐几乎不涨,但内存线性飙升 - 该参数需在
$server->set()中配置,不能靠ini_set()或系统sysctl临时覆盖 - 若用
enable_reuse_port => true,每个 worker 进程都会独立申请缓冲区,要按实际 worker 数再乘一次
worker_num 设多少才不翻车?
worker_num 不是越大越好。设成 CPU 核心数的 2 倍以上,反而会因上下文切换和锁竞争推高延迟,同时让每个 worker 持有的连接缓冲区总和失控。
WebSocket 8.18.2 是该协议规范的一个重要迭代版本,主要优化了连接稳定性与数据传输效率。它通过全双工通信机制,允许客户端与服务器在单一长连接上实时交换数据,大幅降低传统 HTTP 轮询的开销。该版本增强了心跳保活、自动重连及二进制帧传输能力,适用于即时通讯、在线游戏及金融行情推送等低延迟场景,为开发者提供更可靠的实时网络交互基础。
- 推荐公式:
worker_num = swoole_cpu_num() * 1.5(4 核机器设 6,8 核设 12) - 若业务含阻塞 IO(如 MySQL 同步查询),可加 1–2 个额外 worker,但必须搭配
task_worker_num拆离耗时逻辑 - 切忌把
worker_num和max_conn混为一谈:max_conn是连接总数上限,worker_num是处理这些连接的“工人”数量
闭包捕获 $server 或 $frame 导致内存泄漏
在 onMessage 回调里用 go(function () use ($server, $frame) { ... }) 是高频陷阱:协程结束前,$server 和 $frame 的引用不会释放,而 $frame->data 默认是字符串副本,可能带几 MB 的 prompt 或响应内容。
- 只传必要变量,例如
use ($server, $frame->fd, $frame->data)改为use ($server, $fd = $frame->fd, $data = $frame->data) - 避免在闭包里直接引用
$server对象本身,改用$fd+$server->push()显式调用 - 用
memory_get_usage(true)在协程退出前打点,确认是否回落——不回落就说明有隐式引用没断
真正难调的不是参数数字,而是缓冲区、协程生命周期、对象引用三者交织的时机问题:一个 socket_buffer_size 设错,会让所有 worker 的内存水位同步抬高;一个闭包多持有一秒,就可能卡住整个连接池的复用节奏。










