## 现象 `wsutil/broadcaster.go:73-77`: ```go // writeMu 按 Conn 记录串行写锁(#87):……条目不随 // Unregister 删除:在途写可以活得比房间成员身份久,若重注册时换新锁, // 卡死的旧写会与新写放成并发(正是要防的帧损坏)。 writeMu sync.Map // map[Conn]*sync.Mutex ``` `connWriteLock`(broadcaster.go:222-227)只有 `Load/LoadOrStore`,**全文件无任何 `Delete`**;`Close()`(broadcaster.go:270+)只清 rooms 也不同步清理 writeMu。于是每见过一个 Conn 就永久多一条 `Conn→*Mutex` 条目,且 sync.Map 的 key 是强引用——断开的 websocket Conn 对象(及其内部读写缓冲、底层 net.Conn 包装)**永远无法被 GC**。 ## 失败场景推演 长驻广播服务(聊天室/推送/进度流)的客户端轮换是常态(断线重连、App 前后台切换、滚动发布)。每轮换一次泄漏一个 Conn 全量对象:千次/小时的轮换下 RSS 随历史连接总数线性增长、永不回落,数天后 OOM 或内存告警。正确性上毫无症状(帧不坏、测试绿),只有内存一个维度爆。 ## 为什么测试没抓到 现有测试生命周期秒级、断言只看功能(帧正确、房间计数);泄漏不产生断言失败。#87 的修复测试专测帧交错,没有内存维度断言。 ## 建议修复方向 安全回收条件是「conn 不属于任何房间 **且** 写锁空闲(TryLock 成功)」——可在 handleUnregister 收尾处尝试 TryLock 成功后 `writeMu.Delete(conn)`(拿不到锁说明在途写还活着,留待写协程退出时清理);或给锁条目加写者退出标记。至少在 godoc 明示泄漏面与监控口径。 --- 置信度:中高(「无 Delete 路径、sync.Map 持引用」为代码级确定事实;泄漏量级依赖部署形态,故非最高档;基线 = network 9f3d2c3) **与既有 issue 的差异**:#87(帧损坏)正是引入 writeMu 并写下「条目不随 Unregister 删除」的那条 issue,但其正文只论证正确性(防并发写坏帧),**泄漏维度**(无上界增长 + pin Conn)无任何 issue 覆盖。delta:#87 解决「删了会坏」,本条指出「不删会漏」,需要安全回收协议。
Activity
Merge pull request #152 from oekit/fix/sweep-20261111-network
zy84338719 commentedon Nov 10, 2026
已在
v0.10.0修复并发布 ✅变更内容
本条修复(在
v0.10.0的版本节里定位到):该版本 `v0.10.0` 的其余变更
关联问题单:#144。
关联问题单:#143。
关联问题单:#142。
Release: https://github.com/oekit/network/releases/tag/v0.10.0
复核确认:修复已合入 main 且随 v0.10.0 发版,main CI 全绿(wsutil/streamx/mq -race 全过)。