[BUG] Claude Code memory leak causing repeated crashes with Opus 4.6
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
To Reproduce:
(version 2.1.71 - 2.1.74 have all done the same)
- Open 4 Opus/Sonnet chats and use them for 2-3 hours swapping between them.
- Track the memory usage by these processes (track the PID)
- The memory usage will continue to grow until either the Claude (engine) crashes for all 4 at once or the system crashes.
Bug Description
I use largely Claude Code. Recently (last 3 weeks or so), I have started heavy use of Opus 4.6 (medium). It keeps crashing from a memory leak filling up available memory. It is leaving zombie processes that slowly eat up virtual and RAM memory it needs. I have written a prompt to clean it, but I have taken to rebooting often and documenting progress and logs in notepad because Claude is unstable and loses its progress when it crashes. It has crashed about 15 times in last 5 days, even with reboots, resets, memory cleans. here is recent good output from a cleanup command: ---
CLEANUP REPORT
Claude:
Status: normal
Private: 1748 MB / 4096 MB (ok)
Handles: 1417 (ok)
Action: none
Zombies: 0 found
Docker:
Status: not running (skipped)
Containers: n/a
Images: n/a
Volumes: n/a
Temp files: none (venv caches only, left intact)
Claude logs: 19.7 MB (under 20 MB threshold, no trim)
Memory: 17.2 GB free / 31.7 GB total (committed: 21.3 GB)
Disk recovered: 0 GB (system already clean)
Everything looks healthy. Run /cleanup again anytime.
Environment Info
Platform: win32
Terminal: windows-terminal
Version: 2.1.71
Feedback ID: 0e8459c7-44de-4ca2-8558-bcd6fb6edbf5
=========== Actual command used for /cleanup
System & Claude Cleanup
##NOTE: username actual replaced with [UserName]
Clean up Docker resources, zombie processes, Claude memory leaks, and reclaim disk/memory.
Windows PowerShell Command Pattern
CRITICAL: Never pass multi-line PowerShell via -Command "..." — bash will expand $variables
before PowerShell sees them, corrupting the script. Always use this pattern:
- Write the script to a temp
.ps1file using the Write tool - Execute with:
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "C:\...\script.ps1"
All multi-line PowerShell steps below must use this pattern.
Instructions
Run the following cleanup steps in order. Report results after each step.
Step 1: Claude Desktop Memory Leak Check
Write this script to C:\Users\[UserName]\AppData\Local\Temp\check_claude.ps1 then execute it:
$procs = Get-Process -Name 'claude' -ErrorAction SilentlyContinue
if ($procs) {
$main = $procs | Sort-Object PrivateMemorySize64 -Descending | Select-Object -First 1
$mainPrivMB = [math]::Round($main.PrivateMemorySize64 / 1MB)
$totalPrivMB = [math]::Round(($procs | Measure-Object PrivateMemorySize64 -Sum).Sum / 1MB)
$totalHandles = ($procs | Measure-Object HandleCount -Sum).Sum
Write-Host "CLAUDE MEMORY STATUS"
Write-Host " Processes: $($procs.Count)"
Write-Host " Main Private: $mainPrivMB MB $(if($mainPrivMB -gt 4096){'!! LEAKED'}else{'(ok)'})"
Write-Host " Total Private: $totalPrivMB MB"
Write-Host " Handles: $totalHandles $(if($totalHandles -gt 3000){'!! HANDLE LEAK'}else{'(ok)'})"
$procs | Sort-Object PrivateMemorySize64 -Descending |
Select-Object Id,
@{N='RAM_MB';E={[math]::Round($_.WorkingSet64/1MB)}},
@{N='Priv_MB';E={[math]::Round($_.PrivateMemorySize64/1MB)}},
HandleCount, Responding |
Format-Table -AutoSize
} else {
Write-Host "Claude not running"
}
Execute with:
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "C:\Users\[UserName]\AppData\Local\Temp\check_claude.ps1"
If main process private bytes > 4096 MB OR handles > 3000, tell the user:
- Memory leak detected — recommend running the full cleanup script
- Ask: "Run
claude-cleanup.ps1to kill and restart Claude? (This will close any open conversations)"
If user confirms, run:
powershell.exe -ExecutionPolicy Bypass -File "C:\Users\[UserName]\Documents\Claude\Scripts\claude-cleanup.ps1"
If memory is normal, report "Claude memory OK" and continue to next steps.
Step 2: Kill Zombie Python Processes
This is a single-line command — safe to use -Command:
powershell.exe -NoProfile -Command "Get-Process python*, Python* -ErrorAction SilentlyContinue | Select-Object Id, ProcessName, @{N='CPU';E={[math]::Round($_.CPU,1)}}, @{N='MemMB';E={[math]::Round($_.WorkingSet64/1MB)}}, Path | Format-Table -AutoSize"
Ask the user before killing any processes. Safe to kill:
- Orphaned pytest workers
- Stale uvicorn/FastAPI processes not in Docker
- JPype/COMSOL processes from crashed sessions
Do NOT kill:
- IDE Python language servers
- Docker-managed Python processes
- The user's active terminal session
Step 3: Docker Cleanup
Show current Docker disk usage:
docker system df
Then run cleanup commands:
docker container prune -f
docker image prune -f
docker builder prune -f
WARNING: Before pruning volumes, warn the user that this deletes MongoDB data.
Only prune volumes if the user confirms:
docker volume prune -f
For a full nuclear cleanup (user must confirm):
docker system prune -a --volumes -f
Step 4: Temp File Cleanup
List Python caches:
powershell.exe -NoProfile -Command "Get-ChildItem -Path 'D:\LocalGitRepos\OCD-Local' -Recurse -Directory -Filter '__pycache__' -ErrorAction SilentlyContinue | Select-Object -First 20 FullName | Format-Table -AutoSize"
Check COMSOL temp files (single-line, safe to use -Command):
powershell.exe -NoProfile -Command "Get-ChildItem -Path $env:TEMP -Filter 'comsol*' -ErrorAction SilentlyContinue | Select-Object Name, Length, LastWriteTime | Format-Table -AutoSize"
Step 5: Claude Log & Cache Cleanup
Write this script to C:\Users\[UserName]\AppData\Local\Temp\claude_logs.ps1 then execute it:
$logPath = "$env:APPDATA\Claude\logs"
Write-Host "CLAUDE LOG SIZES:"
if (Test-Path $logPath) {
$files = Get-ChildItem $logPath -File -ErrorAction SilentlyContinue
$files | Sort-Object Length -Desc |
Select-Object Name, @{N='MB';E={[math]::Round($_.Length/1MB,1)}} |
Format-Table -AutoSize
$total = [math]::Round(($files | Measure-Object Length -Sum).Sum / 1MB, 1)
Write-Host "Total logs: $total MB"
} else {
Write-Host "Log path not found: $logPath"
}
If total logs > 20 MB, write this trim script to C:\Users\[UserName]\AppData\Local\Temp\trim_logs.ps1:
$logPath = "$env:APPDATA\Claude\logs"
$before = [math]::Round((Get-ChildItem $logPath -File | Measure-Object Length -Sum).Sum / 1MB, 1)
Write-Host "Before: $before MB"
Get-ChildItem $logPath -File | Where-Object { $_.Length -gt 5MB } | ForEach-Object {
try {
$tail = Get-Content $_.FullName -Tail 200 -Encoding utf8 -ErrorAction Stop
$tail | Set-Content $_.FullName -Encoding utf8 -Force
Write-Host "Trimmed: $($_.Name)"
} catch {
Write-Host "Skipped (locked): $($_.Name)"
}
}
$after = [math]::Round((Get-ChildItem $logPath -File | Measure-Object Length -Sum).Sum / 1MB, 1)
Write-Host "After: $after MB"
Execute each script with:
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "C:\Users\[UserName]\AppData\Local\Temp\claude_logs.ps1"
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "C:\Users\[UserName]\AppData\Local\Temp\trim_logs.ps1"
Step 6: Memory Check
Write this script to C:\Users\[UserName]\AppData\Local\Temp\mem_check.ps1 then execute it:
$os = Get-CimInstance Win32_OperatingSystem
$totalGB = [math]::Round($os.TotalVisibleMemorySize / 1MB, 1)
$freeGB = [math]::Round($os.FreePhysicalMemory / 1MB, 1)
$commitGB = [math]::Round(($os.TotalVirtualMemorySize - $os.FreeVirtualMemory) / 1MB, 1)
$totalVirtGB = [math]::Round($os.TotalVirtualMemorySize / 1MB, 1)
Write-Host "SYSTEM MEMORY:"
Write-Host " Total: $totalGB GB"
Write-Host " Free: $freeGB GB"
Write-Host " Committed: $commitGB GB / $totalVirtGB GB"
Write-Host ""
Write-Host "TOP 15 BY MEMORY:"
Get-Process | Sort-Object WorkingSet64 -Desc | Select-Object -First 15 ProcessName,
@{N='MemMB';E={[math]::Round($_.WorkingSet64/1MB)}}, CPU |
Format-Table -AutoSize
Execute with:
powershell.exe -ExecutionPolicy Bypass -NoProfile -File "C:\Users\[UserName]\AppData\Local\Temp\mem_check.ps1"
Response Format
CLEANUP REPORT
------------------------------
Claude:
Status: <normal / LEAKED / restarted>
Private: <main process MB> / 4096 MB
Handles: <count> (<status>)
Action: <none / restarted / user declined>
Zombies: <killed count> / <found count>
Docker:
Containers: <pruned count>
Images: <reclaimed size>
Build cache: <reclaimed size>
Volumes: <pruned or skipped>
Temp files: <cleaned count>
Claude logs: <before MB> -> <after MB>
Memory: <free GB> / <total GB> (committed: <X> GB)
------------------------------
Disk recovered: <total GB reclaimed>
Then say: "Cleanup complete. Run /cleanup again anytime."
What Should Happen?
Not leak zombie processes that crash system.
Error Messages/Logs
Steps to Reproduce
Step 2: Kill Zombie Python Processes
This is a single-line command — safe to use -Command:
powershell.exe -NoProfile -Command "Get-Process python*, Python* -ErrorAction SilentlyContinue | Select-Object Id, ProcessName, @{N='CPU';E={[math]::Round($_.CPU,1)}}, @{N='MemMB';E={[math]::Round($_.WorkingSet64/1MB)}}, Path | Format-Table -AutoSize"
Ask the user before killing any processes. Safe to kill:
- Orphaned pytest workers
- Stale uvicorn/FastAPI processes not in Docker
- JPype/COMSOL processes from crashed sessions
Do NOT kill:
- IDE Python language servers
- Docker-managed Python processes
- The user's active terminal session
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
2.1.71
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Windows Terminal
Additional Information
I used Opus occasionally and Sonnet 4.5 a ton and did not have this issue.
12 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Running into the same issue on MacOS. Claude put a background clean-up process in place. Here's its summary of the situation on my end.
------------------
macOS, same issue — zombie Python processes from Firebase emulator functions-framework workers
Environment: macOS 26.2 (Sequoia), Apple Silicon, Claude Code via Claude Desktop, Python 3.13.12 (Homebrew)
I'm seeing the exact same memory leak pattern. In my case, Claude Desktop spawns Firebase emulator sessions that use Python functions-framework workers. These workers are never reaped — they accumulate silently. I found 3,474 zombie functions-framework processes consuming all available RAM, causing macOS to freeze completely (required hard reboot).
The Python crash reports show crashed on child side of fork pre-exec with performForkChildInitialize in the ObjC runtime — this is a known Python 3.13 + macOS issue where forking after ObjC class initialization causes SIGKILL. The _scproxy module triggers it by calling SCDynamicStoreCopyProxiesWithOptions on a forked child thread.
Workaround: I created a launchd agent that runs a cleanup script every 10 minutes to pkill -9 -f "functions-framework" when the count exceeds 50. This prevents the accumulation. Happy to share the script if others need it.
The root issue seems to be that Claude Code's subprocess management doesn't properly reap child processes when MCP servers or tool invocations spawn their own workers.
thanks @chris-servantium I also have a cleanup script running, and I tried using Sonnet instead of Opus, that did not resolve. I just had 3 parallel chats all crash at the same time, when otherwise the system was not bogging down (that happens at times with this.) It really just seems to be less stable, much less stable, unfortunately. Thanks for your feedback, hopefully this will get identified and fixed soon.
Just and update, the fix above, had side effects of restarting Claude at random times:
From chat about this:
Step 1 — Kills ALL claude processes:
Get-Process -Name "claude" | Stop-Process -Force # line 78
Step 2 — Tries to relaunch Claude Desktop GUI:
$exe = @("...\claude-desktop\Claude.exe", "...\Claude\Claude.exe") | ...
Start-Process $exe # line 120
The problem: You're using Claude Code (CLI), not Claude Desktop.
When the watchdog fires and any threshold is hit, it
kills every process named claude — including your active Claude Code sessions
— then tries to restart a Desktop .exe
that may not exist.
The thresholds that trigger this (from claude-watchdog.ps1):
With Opus 4.6 sessions running 30-60 min, hitting 4GB private memory is exactly what the crash analysis document
describes as normal. So yes — this watchdog is almost certainly what's been killing your sessions.
The fix depends on what you want:
-- I removed any reset of any kind from my automated cleanup..
Yesterday with Version 2.1.74 my system crashed. I have setup extensive tracking and logging, I now am limiting to 2 chat's at same time an /exit of both regularly as work around. I I use 4 at once, the memory will all get used up, /clear does little to actual clear used memory on system, so /exit is needed to reset.
Crash Analysis
Timeline:
┌──────────────┬───────────────────────────────────────────────────┐
│ Time │ Event │
├──────────────┼───────────────────────────────────────────────────┤
│ 10:43 │ PID 5864 (Sonnet, default) starts │
├──────────────┼───────────────────────────────────────────────────┤
│ 11:08 │ Watcher first sees PID 5864 at 776 MB — memory_spike logged │
├──────────────┼───────────────────────────────────────────────────┤
│ 11:12:35 │ PID 3372 starts with --model opus at 445 MB │
├──────────────┼───────────────────────────────────────────────────┤
│ 11:12–11:29 │ PID 3372 climbs steadily: 445 → 500 → 524 → 572 → 602 → 626 → 647 → 747 MB │
├──────────────┼───────────────────────────────────────────────────┤
│ 11:29:35 │ Last sample: 5864=717 MB + 3372=747 MB = 1,465 MB combined │
├──────────────┼───────────────────────────────────────────────────┤
│ 11:30:06.177 │ PID 5864 exits │
├──────────────┼───────────────────────────────────────────────────┤
│ 11:30:06.177 │ PID 3372 exits — 0.0006 seconds later │
└──────────────┴───────────────────────────────────────────────────┘
Root cause: OOM kill. Both processes died within 1ms of each other — that's a kernel-level memory manager kill, not a
normal exit. Two Claude instances (one Sonnet, one Opus) combined to ~1.47 GB and Windows terminated both
simultaneously.
I read over: https://github.com/anthropics/claude-code/issues/33735
thanks @nerdx86 for the nice bug writeup.
It is likely the same fix will help both issues, essentially garbage collection or similar are allowing longer sessions to continue to use more memory, that is consistent.
I am guessing that it's a little different on my system because I have a 64GB laptop that I run 12+ CC sessions on.. But I have them spread across related repos so I have 3 to 8 tasks migrating around the various code bases to work through features. So a little 5GB memory leak is a drop in the bucket and it sits idle for days sometimes.. But when the memory gets 10 to 20gb or I have 8 leaking 5gb each, I start to be affected. Make sense?
This is a memory persistence problem Cathedral addresses -- https://cathedral-ai.com
Free hosted memory API for AI agents.
GET /wakeat every session start returns full identity, core memories, and recent context. Nothing lost between resets.Also has drift detection (
GET /drift) to catch gradual identity shift across sessions. MIT licensed, open source.Long lived threads are continuing to eat more memory over time, even if they are not working at the time (I am working in different thread). As work around have reduced to 2 active chats, so doing about 40% less effective work due to this issue and my having to allow for it. Considering moving off Claude, as they have had zero feedback on this in what I have seen.
I am now running Claude Code v2.1.89, and seeing less crashes, but I have not heard that the memory issue is complete, it would be good to resolve and close out memory issues reported if the bug has been fixed. I have seen my entire OS go down due to Claude since this was first reported, which demonstrates ongoing issues of memory management.
Running Claude Code v2.1.90 After some long runs largely with Opus and this issues seems to be resolved.
I will close it out, thanks for fixing!
(Utility I have for dealing with this issue reports systems in good shape):
● CLEANUP REPORT
------------------------------
Claude:
Status: HANDLE_LEAK (handles ok per process, total 5370 across 11)
Private: 1888 MB / 4096 MB (ok)
Handles: 5370 (threshold 3000) — distributed across 11 instances
Services: 5 [NewSoftware] services stopped (api_gateway, training,
inference, simulation, engine_gateway)
Zombies: 0 killed — per project policy, processes reported only
(see feedback_no_kill_processes.md)
Notable: PID 49456 — uv python 345 MB RAM
PID 36244 — uv python 654 CPU (active)
PID 23112 — uv python 20 MB (likely watch_processes.py)
APP tmp: No stale APP temp files
__pycache__: 992 dirs (in .venv + source — normal, not cleaned)
Claude logs: 3.9 MB (under 20 MB threshold — no trim needed)
Memory: 19.5 GB free / 31.7 GB total (committed: 36.7 GB)
------------------------------
Disk recovered: 0 MB (nothing to prune)
Notes:
individual handle counts are normal (258–1205)
This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.