10 Orphaned zsh Processes Pinned 10 Cores at 60% Each
A Claude Code session left behind 10 orphaned busy-loops that saturated a 10-core MacBook for nearly two days. The load average hit 122 on 10 cores. The culprit: while :; do :; done spawned across all cores, never cleaned up.
The Tell: PPID 1 and High CPU
uptime showed load averages 122.91, 167.84, 162.08 — on a 10-core machine, that's not idle. ps -Ao pcpu,pid,ppid,user,comm -r | head -12 revealed 10 zsh processes each at ~60% CPU, all with PPID 1. That's the smoking gun: their parent died and launchd adopted them.
The Arguments Reveal Everything
ps -o pid,lstart,etime,pcpu,args -p 94279,94280,94281 showed:
/bin/zsh -c source ~/.claude/shell-snapshots/snapshot-zsh-XXXX.sh 2>/dev/null || true && eval '
SP=/private/tmp/claude-501///scratchpad
# saturate all cores, then run the suite under contention
NCPU=$(sysctl -n hw.ncpu)
for i in $(seq 1 $NCPU); do (while :; do :; done) & done
LOADPIDS=$(jobs -p)
pnpm test:integration > "$SP/load.log" 2>&1
kill $LOADPIDS 2>/dev/null
...'
Elapsed time: 01-22:41:17 — nearly two days.
Why Cleanup Failed
Two bugs in the script:
-
jobs -preturns nothing in non-interactive shells. Job control is off, soLOADPIDSwas empty andkillhad no effect. Fix: collect$!after each background spawn. -
No trap. The parent shell died before reaching the
killline (likely from the test suite or a crash). Atrapon EXIT/INT/TERM would have killed the spinners.
How to Fix It
Plain kill worked — no -9 needed:
kill 94279 94280 94281 94282 94283 94284 94285 94286 94287 94288
Afterwards, Chrome was back on top at 129% CPU and nothing else broke 30%.
How to Check Your Machine
uptime # load average well above your core count?
sysctl -n hw.ncpu # what your core count actually is
ps -Ao pcpu,pid,ppid,user,comm -r | head -15
Look for processes with PPID 1, high CPU, and long elapsed time. Get the full argument list:
ps -o pid,ppid,lstart,etime,pcpu,args -p
Takeaway
Agent-generated scripts can leave orphaned processes. Always use trap and collect PIDs with $!. A quick ps check would have caught this two days earlier.



