[PR #10914] fix(opencode): resolve multiple memory leaks in long-running sessions #13604

Open
opened 2026-02-16 18:18:27 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/anomalyco/opencode/pull/10914

State: open
Merged: No


What does this PR do?

Fixes 6 memory leaks that cause RSS to grow continuously during long-running sessions. Changes are minimal and focused — 79 insertions, 25 deletions across 6 files.

Changes:

File Issue Fix
util/queue.ts AsyncIterator loops forever, no termination Add close()/drain(), iterator exits on close
tool/bash.ts output += chunk.toString() unbounded Buffer[] ring buffer, 10MB cap
lsp/client.ts diagnostics Map never cleared clear() on shutdown, 5000 entry cap
bus/index.ts subscriptions Map not cleared on dispose subscriptions.clear() in dispose callback
pty/index.ts buffer += data then slice() GC pressure Buffer[] array, avoid string reallocation
index.ts disposeAll() not called on exit Add to finally block

How did you verify your code works?

  1. TypeScript check passes — tsc --noEmit reports no errors in modified files
  2. All changes are additive to existing cleanup paths (dispose callbacks, shutdown methods)
  3. AsyncQueue close()/drain() are new methods — existing callers are unaffected since they don't call close()
  4. Buffer ring strategy preserves existing behavior (output content, metadata truncation) while capping memory

Fixes #10913

**Original Pull Request:** https://github.com/anomalyco/opencode/pull/10914 **State:** open **Merged:** No --- ### What does this PR do? Fixes 6 memory leaks that cause RSS to grow continuously during long-running sessions. Changes are minimal and focused — 79 insertions, 25 deletions across 6 files. **Changes:** | File | Issue | Fix | |------|-------|-----| | `util/queue.ts` | AsyncIterator loops forever, no termination | Add `close()`/`drain()`, iterator exits on close | | `tool/bash.ts` | `output += chunk.toString()` unbounded | `Buffer[]` ring buffer, 10MB cap | | `lsp/client.ts` | diagnostics Map never cleared | `clear()` on shutdown, 5000 entry cap | | `bus/index.ts` | subscriptions Map not cleared on dispose | `subscriptions.clear()` in dispose callback | | `pty/index.ts` | `buffer += data` then `slice()` GC pressure | `Buffer[]` array, avoid string reallocation | | `index.ts` | `disposeAll()` not called on exit | Add to `finally` block | ### How did you verify your code works? 1. TypeScript check passes — `tsc --noEmit` reports no errors in modified files 2. All changes are additive to existing cleanup paths (dispose callbacks, shutdown methods) 3. AsyncQueue `close()`/`drain()` are new methods — existing callers are unaffected since they don't call `close()` 4. Buffer ring strategy preserves existing behavior (output content, metadata truncation) while capping memory Fixes #10913
yindo added the pull-request label 2026-02-16 18:18:27 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: anomalyco/opencode#13604