Skip to content

12.9 BoundedUUIDSet:有界 UUID 集合与防内存泄漏

路径docs/part12-bridge/09-bounded-uuid-set.md
系列:Claude Code 完全指南 V2 · 第 12 篇


学习目标

完成本节学习后,你应该能够:

  1. 解释 为何 Bridge 需要 有界 的 UUID 集合:长时间运行 + 高频 idSet 无限增长 风险。
  2. 描述 BoundedUUIDSet 的典型语义:addhas淘汰策略(FIFO、LRU)。
  3. 权衡 误判(Bloom 过滤) vs 精确(纯 Set + 上限)。
  4. 关联 sessionRunner(12.6):活跃会话历史 id 去重 的不同需求。

生活类比:门禁卡回收桶

公司发卡(UUID)记录 谁进过门。若只进不出,办公室堆满 废卡盒内存泄漏)。有界桶策略:最多保留最近 N 张卡复印件——旧复印件扔掉,但 仍在有效期 的卡 另有权威登记会话表)。


问题场景

场景需要 Bounded?
已处理通知 id
当前会话 Mapdispose 而非盲目增长
调试日志索引可落盘而非内存

API 形状(示意)

typescript
class BoundedUUIDSet {
  constructor(private readonly maxSize: number) {}

  add(id: string): boolean {
    // 返回是否首次出现
  }

  has(id: string): boolean {}

  get size(): number {}
}

实现策略对比

策略优点缺点
Set + 队列精确、实现简单has O(1),淘汰 O(1)
Map + LRU可刷新热点稍复杂
Bloom Filter省内存假阳性

Bridge 防重放若不能容忍假阳性,优先 精确结构


源码片段:Set + 队列(示意)

typescript
class BoundedUUIDSet {
  private readonly set = new Set<string>();
  private readonly q: string[] = [];

  constructor(private readonly maxSize: number) {}

  add(id: string): boolean {
    if (this.set.has(id)) return false;
    this.set.add(id);
    this.q.push(id);
    while (this.q.length > this.maxSize) {
      const old = this.q.shift()!;
      this.set.delete(old);
    }
    return true;
  }

  has(id: string): boolean {
    return this.set.has(id);
  }
}

与 sessionRunner 的边界

结构职责
Map<SessionId, Session>权威活跃会话
BoundedUUIDSet短期去重(通知 id / 重试)

勿用 Bounded 结构代替会话释放逻辑


参数选择

参数经验直觉
maxSize峰值 QPS × TTL窗口 相关
监控bounded_set_evictions_total

并发

多线程语言需 ;Node 单线程 也要注意 async 交错 —— 批量 add 时在 同一 tick 内完成。


小结

BoundedUUIDSet小工具、大收益:防止 边缘路径长期进程 拖死。最后一节 12.10 总结


自测

  1. 队列淘汰后 旧 id 再来 会被如何判断?是否符合你的 防重放 语义?
  2. 为何 LRU 有时优于 FIFO?

术语

英文中文
eviction淘汰
LRU最近最少使用

测试用例

  • maxSize=3 序列 a b c dhas(a) 期望?
  • 并发 1e5 随机 uuid 内存平台稳定。

实战题

jti 需要 强吊销(12.5),BoundedSet 不够——应补充什么存储?


伪代码:LRU Map

typescript
// 使用 Map 迭代顺序:最近插入在末尾
function touch(m: Map<string, true>, id: string, max: number) {
  if (m.has(id)) m.delete(id);
  m.set(id, true);
  while (m.size > max) {
    const first = m.keys().next().value;
    m.delete(first);
  }
}

与 31 文件

该结构常是 独立 util,被 bridgeMain通知子系统 引用。


监控告警

淘汰速率 持续高于预期,可能 maxSize 过小攻击重放


结语

工程魅力常在 边界条件有界数据结构成熟后端本能 在 Bridge 中的投影。


与其他「有界」结构类比

结构用途
有界队列限制待处理 RPC 深度
Ring buffer 日志限制内存中 最近 N 条 诊断
BoundedUUIDSet限制 去重/防重放 集合

统一哲学:长期进程中的任何无限集合都要么落盘,要么有界。


复杂度小结

操作Set+队列实现
add均摊 O(1)
hasO(1)
空间O(maxSize)

maxSize 为几千到几万量级时,对 Bridge 微不足道;换来 可预测的内存上界

本项目仅用于教育学习目的。Claude Code 源码版权归 Anthropic, PBC 所有。