## Reference Retention (Medium)

### Trigger Signals

- Objects holding mutual strong references forming cycles (A→B→A), especially via callbacks, closures, observer patterns
- Closures capturing external variables but closure lifetime exceeds expectation (e.g., closure stored in long-lived object)
- Large objects cached without eviction strategy (e.g., full query results cached without size limit)
- Scenarios missing `WeakRef`/`WeakReference` (parent→child strong reference + child→parent callback forming cycle)

### Judgment Process

1. **Identify reference relationship graph**: `find_references` tracks object reference holdings:
   - Class member variables holding references to other objects
   - External variables captured by closures
   - `this` or object references passed during callback/listener registration
2. **Check circular references**: `Read` analyzes the reference relationship graph, determining whether cycles exist:
   - Parent-child relationships: parent.children.push(child) + child.onEvent = parent.handler
   - Observer patterns: subject.observers.push(observer) + observer.subject = subject
   - Closure cycles: `fn() { obj.callback = () => { obj.method() } }`
3. **Check closure lifetime**: `Read` confirms whether closures are stored in long-lived containers (global variables, class members, caches), while the closure captures short-lived objects
4. **Check cache eviction strategy**: `Read` confirms whether cache has:
   - Size limit (max entries, max memory)
   - Eviction strategy (LRU, TTL, periodic cleanup)
   - Using `WeakRef`/`WeakReference`/`WeakReference<T>` to avoid preventing GC

### Evidence Construction

After confirming a defect, the output must include:
- Reference cycle path (complete reference chain A→B→...→A)
- Closure capture analysis (which variables are captured, where they are stored)
- Cache eviction gap (no size limit or no eviction strategy)
- Business impact (continuous memory growth, increased GC pressure, eventual OOM)

### Exclusions

- Already using `WeakRef`/`WeakReference` to break reference cycles
- Already using `removeEventListener`/`off` to clean up on object destruction
- Cache implementations with clear TTL and size limits
- Short-term caches with clear lifecycle (request-level caches)
