Skip to content

fix(memory): resolve 6 memory leak issues in long-running sessions - #12053

Closed
sgInnora wants to merge 1 commit into
anomalyco:devfrom
sgInnora:fix/memory-leaks-v2
Closed

fix(memory): resolve 6 memory leak issues in long-running sessions#12053
sgInnora wants to merge 1 commit into
anomalyco:devfrom
sgInnora:fix/memory-leaks-v2

Conversation

@sgInnora

Copy link
Copy Markdown

Summary

This PR addresses 6 memory leak issues observed during long-running coding sessions (8+ hours). The fixes target critical areas where memory accumulates unboundedly.

Problem

During extended usage, opencode's memory footprint grows continuously, eventually causing performance degradation or crashes. Root causes identified:

  1. AsyncQueue resolver accumulation - Pending resolvers never get cleaned up
  2. Bash output string concatenation - Unbounded string growth in let output = ""
  3. LSP diagnostics Map growth - No eviction policy for stale file diagnostics
  4. Bus subscription leaks - Subscriptions not cleared on dispose
  5. PTY buffer string concatenation - String-based buffer causes allocation pressure
  6. Process exit cleanup - Instance resources not disposed on exit

Changes

FileIssueFix
util/queue.tsResolvers accumulate foreverAdd close() and drain() methods, handle closed state
tool/bash.tsoutput += chunk grows unboundedRing buffer with 10MB cap using Buffer[]
lsp/client.tsDiagnostics Map grows infinitelyFIFO eviction at 5K files, clear() on shutdown
bus/index.tsSubscriptions leaksubscriptions.clear() on dispose
pty/index.tsString buffer allocation pressureBuffer[] ring buffer replacing string concatenation
index.tsResources not cleaned on exitCall Instance.disposeAll() in finally block

Technical Details

AsyncQueue (Critical)

// Before: Resolvers accumulate foreverprivateresolvers: ((value: T)=>void)[]=[]// After: Proper cleanup on closeclose(){this.closed=truefor(constresolveofthis.resolvers)resolve(undefined)this.resolvers.length=0}

Bash Tool (Critical)

// Before: Unbounded string growthletoutput=""output+=chunk.toString()// After: 10MB ring bufferconstMAX_OUTPUT_BYTES=10*1024*1024constoutputChunks: Buffer[]=[]while(outputSize>MAX_OUTPUT_BYTES&&outputChunks.length>1){constdropped=outputChunks.shift()!outputSize-=dropped.length}

LSP Client (High)

// Before: No limit on diagnosticsconstdiagnostics=newMap<string,Diagnostic[]>()// After: FIFO eviction at 5K filesconstMAX_DIAGNOSTICS_FILES=5000if(!exists&&diagnostics.size>=MAX_DIAGNOSTICS_FILES){constoldest=diagnostics.keys().next().valueif(oldest!==undefined)diagnostics.delete(oldest)}

Testing

  • Tested on macOS with Apple Silicon (M3 Max)
  • Monitored RSS over 8+ hour sessions
  • Memory growth stabilized after applying fixes

Related

This is a resubmission based on the latest dev branch. Previous discussions may exist in earlier PRs.


Submitted by andy_feng (feng@innora.ai) from Innora Team

- AsyncQueue: Add close() and drain() methods to prevent resolver leaks
- Bash tool: Replace unbounded string concatenation with 10MB ring buffer
- LSP client: Add FIFO eviction (5K limit) for diagnostics Map + clear on shutdown
- Bus: Clear all subscriptions on dispose to prevent listener accumulation
- PTY: Replace string buffer with Buffer[] ring buffer to reduce allocation pressure
- Index: Call Instance.disposeAll() on process exit to ensure cleanup
These fixes address memory growth observed in 8+ hour coding sessions.
Tested on macOS with M3 Max, monitoring RSS over extended usage periods.
@github-actions

Copy link
Copy Markdown
Contributor

Thanks for your contribution!

This PR doesn't have a linked issue. All PRs must reference an existing issue.

Please:

  1. Open an issue describing the bug/feature (if one doesn't exist)
  2. Add Fixes #<number> or Closes #<number> to this PR description

See CONTRIBUTING.md for details.

@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Based on my search results, I found 2 potentially related PRs:

  1. PR fix(opencode): resolve multiple memory leaks in long-running sessions #10914 - fix(opencode): resolve multiple memory leaks in long-running sessions

  2. PR fix: add LRU eviction to LSP client file and diagnostics tracking #7050 - fix: add LRU eviction to LSP client file and diagnostics tracking

  3. PR fix(core): add dispose functions to prevent subscription memory leaks #7032 - fix(core): add dispose functions to prevent subscription memory leaks

I recommend checking PR #10914 first, as it's most likely the previous attempt at fixing the same set of memory leak issues.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@sgInnora