php websocket长连接内存不释放的主因是未显式调用fclose()和unset()清理socket资源;必须每次通信后手动关闭并销毁流,配合内存监控与强制gc,禁用file_get_contents/curl等不支持websocket协议的函数。

PHP 连接 WebSocket 时内存不释放的典型表现
用 fsockopen 或 stream_socket_client 建立长连接后,反复收发消息却没调用 fclose 或未 unset 流资源,会导致 PHP 进程内存持续上涨;在 CLI 模式下跑守护进程(如监听 WebSocket server 消息)时尤其明显,几小时后可能吃光几百 MB 内存。
stream_socket_client 必须手动清理资源
PHP 不会自动回收 socket 流,即使连接已断开或变量超出作用域。必须显式关闭并置空:
- 每次通信完成后立即调用
fclose($socket),不要依赖脚本结束时自动释放 - 关闭后建议执行
unset($socket),避免因引用残留导致 GC 无法回收 - 若使用循环重连逻辑,确保每次迭代前检查
is_resource($socket),防止对已关闭资源重复操作
示例关键片段:
if (is_resource($socket)) {
fclose($socket);
unset($socket);
}
用 set_time_limit(0) + 内存监控防失控
CLI 下长运行容易掩盖内存问题,需主动干预:
立即学习“PHP免费学习笔记(深入)”;
- 每处理 N 条消息后调用
memory_get_usage(true)检查实际分配内存(非 peak) - 当内存超过阈值(如 32MB),强制
gc_collect_cycles()并重新建立连接 - 务必搭配
set_time_limit(0)防止超时中断,但要自己实现心跳与重连超时控制
别用 file_get_contents 或 cURL 连 WebSocket
这两个函数根本不支持 WebSocket 协议握手和帧解析:
-
file_get_contents('ws://...')会直接报错failed to open stream: Unable to find the wrapper "ws" - cURL 默认不处理
Sec-WebSocket-Accept校验和掩码解包,强行模拟易出错且无流控能力 - 真要简化开发,用
ext-websocket(PECL 扩展)或ratchet/pawl等成熟客户端库,它们内部已封装资源生命周期管理
原生 socket 是最可控的方式,但代价是每个连接都得亲手管好打开、读写、关闭、销毁四步——漏掉任何一环,内存就悄悄涨上去。











