Skip to content

[wsutil] Broadcaster.writeMu 对每个历史 Conn 永久留存锁条目——轮换型推送服务内存无上界,sync.Map 持引用把已断开的 Conn 连同缓冲一起钉死 #142

Closed

Description

@zy84338719

现象

wsutil/broadcaster.go:73-77:

// 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

  1. moved this from Todo to In Progress in oekit Issue 大盘on Nov 10, 2026
  2. added a commit that references this issue on Nov 10, 2026
  3. moved this from In Progress to Done in oekit Issue 大盘on Nov 10, 2026
  4. zy84338719 commented on Nov 10, 2026

    @zy84338719
    ContributorAuthor

    已在 v0.10.0 修复并发布 ✅

    变更内容

    本条修复(在 v0.10.0 的版本节里定位到):

    该版本 `v0.10.0` 的其余变更

    关联问题单:#144。

    关联问题单:#143。

    关联问题单:#142。

    • 现代语言特性(贴合处落地):clear(Broadcaster.Close 丢弃条目表)、for range int(churn 轮换回归)、errors.Join(并发 emit/close 错误聚合)、sync.Once(SSESink.Close 幂等——「仅首次返回结果」口径贴 nats.Close 先例,故用 Do + 局部结果而非 OnceValue 的结果缓存形态)

    Release: https://github.com/oekit/network/releases/tag/v0.10.0

    复核确认:修复已合入 main 且随 v0.10.0 发版,main CI 全绿(wsutil/streamx/mq -race 全过)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions