## 引用残留（Medium）

### 触发信号

- 对象互相持有强引用形成环（A→B→A），尤其通过回调、闭包、观察者模式
- 闭包捕获外部变量，但闭包生命周期超出预期（如闭包被存储在长生命周期对象中）
- 大对象被缓存但无淘汰策略（如缓存了完整查询结果但无大小上限）
- 缺少 `WeakRef`/`WeakReference` 的场景（父→子强引用 + 子→父回调形成环）

### 判定流程

1. **识别引用关系图**：`find_references` 追踪对象的引用持有关系：
   - 类成员变量持有其他对象的引用
   - 闭包捕获的外部变量
   - 回调/监听器注册时传入的 `this` 或对象引用
2. **检查循环引用**：`Read` 分析引用关系图，判断是否存在环：
   - 父子关系：parent.children.push(child) + child.onEvent = parent.handler
   - 观察者模式：subject.observers.push(observer) + observer.subject = subject
   - 闭包环：`fn() { obj.callback = () => { obj.method() } }`
3. **检查闭包生命周期**：`Read` 确认闭包是否被存储在长生命周期容器中（全局变量、类成员、缓存），而闭包捕获了短生命周期对象
4. **检查缓存淘汰策略**：`Read` 确认缓存是否有：
   - 大小上限（max entries、max memory）
   - 淘汰策略（LRU、TTL、定期清理）
   - 使用 `WeakRef`/`WeakReference`/`WeakReference<T>` 避免阻止 GC

### 证据构造

确认缺陷后，输出需包含：
- 引用环路径（A→B→...→A 的完整引用链）
- 闭包捕获分析（捕获了哪些变量，存储在哪里）
- 缓存淘汰缺失（无大小上限或无淘汰策略）
- 业务影响（内存持续增长、GC 压力增大、最终 OOM）

### 排除

- 已使用 `WeakRef`/`WeakReference` 打断引用环
- 已使用 `removeEventListener`/`off` 在对象销毁时清理
- 有明确 TTL 和大小限制的缓存实现
- 生命周期明确的短期缓存（请求级缓存）
