-
Notifications
You must be signed in to change notification settings - Fork 14.8k
LSP processes remain as orphaned zombie processes after opencode exits, causing severe memory leaks #18632
Description
Summary
After closing opencode, multiple LSP server processes remain running in the background indefinitely, consuming significant system memory. This appears to be a systematic issue with process lifecycle management rather than an isolated bug.
Environment
- OpenCode version: Latest (built from source)
- OS: macOS (darwin/arm64)
- Node/Bun: Bun runtime
- Installation:
npm install -g opencode-ai
Current Behavior
When opencode is launched and then closed, LSP server processes spawned for various projects remain alive as orphaned processes:
# After running opencode a few times across different projects
$ ps aux | grep opencode | grep -v grep | wc -l
20
# Memory consumption per process
$ ps aux | grep opencode.*-c | awk '{sum += $6} END {print sum/1024 " MB"}'
~1.2 GBRoot Cause Analysis (from Source Code Review)
1. Missing Process Signal Handlers
In packages/opencode/src/index.ts, only SIGHUP is handled:
process.on("SIGHUP", () => process.exit())Missing: SIGTERM, SIGINT handlers for graceful shutdown.
2. Forced Exit Without Cleanup Time
packages/opencode/src/index.ts:215:
finally {
// Some subprocesses don't react properly to SIGTERM...
process.exit() // Immediately kills process, no cleanup time for LSP
}This forces immediate exit without allowing Instance.dispose() or State.dispose() to complete.
3. Instance Cache Never Expires
packages/opencode/src/project/instance.ts:15:
const cache = new Map<string, Promise<Context>>() // Permanent cache, no TTLInstances (and their LSP clients) are never cleaned up automatically.
4. LSP Processes Not Properly Tracked
packages/opencode/src/lsp/server.ts uses spawn() without process group management:
- No
detached: truewith process group tracking - Parent death doesn't trigger automatic child cleanup
- Each new project creates new LSP servers that outlive the parent
5. State Disposal Timing Issues
packages/opencode/src/project/state.ts:39-46 warns about disposal taking too long (10s timeout), but the forced process.exit() in index.ts prevents disposal from completing at all.
Expected Behavior
- When opencode exits (normally or via signal), all child LSP processes should be terminated
- LSP servers should have idle timeout to auto-cleanup
- Orphaned processes from previous runs should be detected and cleaned up
Steps to Reproduce
- Open a project with opencode:
opencode - Work for a while (LSP servers will spawn)
- Close opencode (Ctrl+C or normal exit)
- Check for lingering processes:
ps aux | grep opencode.*-c - Repeat with different projects - processes accumulate
Proposed Solutions
Short-term (User Workaround)
Add to shell configuration:
# Kill orphaned opencode LSP processes on terminal exit
trap 'pkill -f "opencode.*-c"' EXITLong-term (Code Fixes)
-
Add signal handlers in
index.ts:process.on("SIGTERM", gracefulShutdown) process.on("SIGINT", gracefulShutdown) async function gracefulShutdown() { await Instance.disposeAll() process.exit(0) }
-
Remove forced exit in index.ts finally block, or add delay:
finally { // Give time for cleanup before forcing exit await new Promise(r => setTimeout(r, 2000)) process.exit() }
-
Add LSP idle timeout in
lsp/index.ts:// Auto-shutdown LSP servers after idle period setTimeout(() => { if (noRecentActivity) client.shutdown() }, IDLE_TIMEOUT)
-
Process group management in
lsp/server.ts:spawn(command, args, { detached: true, // Track PIDs for cleanup })
Impact
- Memory: Each LSP process consumes 50-100MB, easily accumulating to 1-2GB+
- System resources: Zombie processes consume file descriptors and CPU cycles
- User experience: System slowdown, need for manual cleanup
Related Code References
packages/opencode/src/index.ts:52, 215packages/opencode/src/project/instance.ts:15, 103-105packages/opencode/src/project/state.ts:31-69packages/opencode/src/lsp/server.ts(all spawn calls)packages/opencode/src/lsp/client.ts:238-244(shutdown method exists but not called)packages/opencode/src/lsp/index.ts:141-144(dispose handler registered but not triggered)
Severity: High - affects all users with multi-project workflows
Type: Bug / Memory Leak