Uh oh!
There was an error while loading. Please reload this page.
fix(opencode): reduce memory usage and database bloat in long-running instances - #16730
fix(opencode): reduce memory usage and database bloat in long-running instances#16730BYK wants to merge 5 commits into
Conversation
Hey! Your PR title Please update it to start with one of:
Where See CONTRIBUTING.md for details. |
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
binarydoubling
commented
Mar 9, 2026
Hey! We have a complementary PR at #16695 that tackles the in-memory side of these leaks — event listener accumulation in the TUI, unbounded Maps/Sets in the bus/RPC/LSP subsystems, timer/interval cleanup, and session data not being freed on switch. Between the two PRs, most of the memory growth paths should be covered. |
BYK
commented
Mar 9, 2026
Thanks for flagging! Checked #16695 — there are 3 overlapping files but the changes are complementary:
The rest is non-overlapping: our PR covers database health (auto-vacuum, WAL checkpoint, incremental vacuum), bash output spooling, compaction data clearing, Levenshtein optimization, FileTime cleanup, and session retention. Their PR covers TUI event listener leaks, bus tombstones, PTY buffer cleanup, model refresh interval, and share-next disposal. Between the two PRs most memory growth paths should indeed be covered 👍 |
9c9bd4c to
7801ebcComparef5b5f2c to
3a8c120Compare…g in memory Previously, bash tool and /shell command accumulated ALL stdout/stderr in an unbounded string — a verbose command could grow to hundreds of MB. Now output beyond Truncate.MAX_BYTES (50KB) is streamed directly to a spool file on disk. Only the first 50KB is kept in memory for the metadata preview. The full output remains recoverable via the spool file path included in the tool result metadata.
- LSP: delete diagnostic entries when server publishes empty array instead of keeping empty arrays in the map forever - RPC: add 60s timeout to pending calls so leaked promises don't accumulate indefinitely - FileTime: skip (already handled by Effect InstanceState migration)
BYK
commented
Apr 9, 2026
Closing — changes have been incorporated into dev. |
Issue for this PR
Closes#16777
Type of change
What does this PR do?
A long-running OpenCode server (2+ days) was consuming 1.76 GB (602 MB RSS + 1.15 GB swap) on an 8 GB system. The database grew to 1.99 GB (274K parts, 1,706 sessions spanning 53 days) with no automatic cleanup. This PR fixes several root causes:
Database health (
storage/db.ts,project/bootstrap.ts): Enable incremental auto-vacuum (one-time migration) so disk space is reclaimed on deletes. Add periodic WAL checkpoint (every 5 min) and incremental vacuum (hourly) via Scheduler.Bash/shell output spooling (
tool/bash.ts,session/prompt.ts): Both accumulated ALL stdout/stderr in an unbounded in-memory string. Now output beyond 50 KB streams to a spool file on disk. Only a 50 KB preview stays in memory. Full output is recoverable via the spool file path in metadata.Compaction clears dead data (
session/compaction.ts): Compacted tool parts kept their full output in SQLite even thoughtoModelMessages()skips them. Now clears output/metadata/attachments on compaction.Levenshtein optimization (
tool/edit.ts): Replace O(n×m) full-matrix with O(min(n,m)) 2-row algorithm. For 10K char strings: ~400 MB → ~40 KB. Identical results.Memory leak fixes (
file/time.ts,lsp/client.ts,util/rpc.ts): Clean FileTime per-session state on archive/delete. Delete empty LSP diagnostics map entries. Add 60s timeout to RPC pending calls.Session retention (
session/index.ts,config/config.ts): Auto-delete archived sessions older thanretention.days(default 90, 0 = disabled). Runs every 6 hours, batched at 100 per run.How did you verify your code works?
Screenshots / recordings
N/A — backend changes only.
Checklist