Repository navigation
session_diff stores full file contents via git show, causes multi-GB memory on resume #20990
Description
Description
Snapshot.diffFull() in packages/opencode/src/snapshot/index.ts stores entire file contents in FileDiff.before and FileDiff.after via git show. These are persisted as JSON in ~/.local/share/opencode/storage/session_diff/<sessionID>.json and eagerly loaded on session resume.
In active repos with large files, these blobs grow to hundreds of MB per session. On our system:
593M ses_3217a01c8ffeGbwxVoc2sfyYvb.json
593M ses_321604e22ffeISyOc0LrkFJPUr.json
416M ses_70361c737dbd27DXqU8FuEWBoA.json
...
44G total in ~/.local/share/opencode/storage/session_diff/
Resuming a session with a 115MB diff file immediately spikes RSS to 4-10GB as JSON.parse() materializes all the strings. This is a major contributor to the memory issues tracked in #20695.
Root Cause
Two compounding issues:
-
diffFull()stores full file contents, not diffs. Lines 471-472 ofsnapshot/index.ts:git([...cfg, ...args(["show", `${from}:${file}`])]).pipe(Effect.map((item) => item.text)), git([...cfg, ...args(["show", `${to}:${file}`])]).pipe(Effect.map((item) => item.text)),
For a 10MB JSON file, this stores 10MB in
beforeand 10MB inafter. -
The diff covers the entire repo, not just the session's changes.
diffFull()compares two git snapshots (fromandto). In repos with concurrent activity (multiple agents, CI), the diff includes files modified by other sessions. A planning-only session that wrote 3 markdown files ends up with 22 files and 112MB of test fixtures it never touched.This is worse with jj (Jujutsu) co-located repos where the git working copy always has changes.
Evidence from heap snapshots
Heap snapshot analysis (uploaded to #20695) confirms FileDiff.before/after strings dominate the JS heap:
- Snapshot 1 (2.5GB RSS): 355MB in a single diffs
Array(22923)— 51% of JS heap - Snapshot 2 (11GB RSS): 7.64GB of strings, 96% growth from diff content
- TUI snapshot: 22 copies of a 20MB string retained by
property:after
Suggested Fix
- Don't store full file contents. Store unified diffs (
git diff) or just file metadata (name, additions, deletions, status). The full content can be reconstructed from git on demand. - Scope diffs to session's own changes. Don't include files modified by other sessions/agents.
- Don't eagerly load diffs on resume. Load lazily when the review UI actually needs them.
- Cap content size. If
before.length + after.length > limit, store only metadata.
Steps to reproduce
- Start a session in a repo with large tracked files (>1MB)
- Let other activity (commits, CI) happen in the repo
- Close and resume the session
- Observe RSS spike on resume proportional to
session_difffile size
Environment
- OpenCode 1.3.13
- Ubuntu 22.04, 247GB RAM
- jj (Jujutsu) co-located repo with ~100 concurrent agent sessions
- 44GB total session_diff storage across all sessions
Activity
github-actions commentedon Apr 4, 2026
This issue doesn't fully meet our contributing guidelines.
What needs to be fixed:
Please edit this issue to address the above within 2 hours, or it will be automatically closed.
This issue might be a duplicate of existing issues. Please check:
Snapshot.diffFull()storing full file contents inFileDiff.before/after, causing oversized payloads and memory issues on session resumeSnapshot.diffFull()If you believe this was flagged incorrectly, please let a maintainer know.
sjawhar commentedon Apr 4, 2026
Closing as duplicate of #17622 and #11802. Adding our profiling data (heap snapshots, memleak traces, 44GB of session_diff files) to those issues.