gotchabashnextjsMajor
macOS dev machine swapping: ps RSS hides the culprits — use top MEM/CMPRS; long-lived next dev and Docker VM are the usual hogs
Viewed 0 times
Next.js 16 (Turbopack dev), Docker Desktop on Apple Virtualization, Supabase CLI 2.x
slow macswap exhaustedmemory footprintcompressed memorynext dev memory leakdocker desktop memorysupabase analyticsrosetta node
macosdockernodejs
Error Messages
Problem
A 16 GB Apple Silicon Mac running agent sessions, a local Supabase stack in Docker, a
next dev server and a headless browser becomes extremely slow (load 20+ on 8 cores, 29 GB swap used). Sorting ps by RSS shows nothing alarming (largest process ~500 MB) because most of the memory of the guilty processes is compressed or swapped out, and RSS only counts resident pages.Solution
Measure footprint, not RSS:
top -l 1 -o mem -stats pid,ppid,mem,cmprs,command (MEM includes compressed memory; CMPRS shows how much of it is compressed), and sysctl -n vm.swapusage. Group by app family. Typical findings and fixes: (1) a next dev (Turbopack) server left running for days grew to a 9 GB footprint (8.9 GB compressed) inside the single next-server process: restart the dev server between work sessions by killing its whole process group (kill -TERM -<pgid>) and relaunching. (2) Docker Desktop reserving 8 GB for its VM while containers use ~2.3 GB (docker stats --no-stream): lower the VM memory limit. (3) The local Supabase analytics (Logflare) and vector containers used ~0.8 GB and ~55% of a core for logs nobody reads: docker stop them when the app does not use the logs API. (4) Other VMs from desktop apps show up as com.apple.Virtualization.VirtualMachine; lsof -p <pid> shows which disk image they opened, which identifies the owner. (5) Long-forgotten terminal sessions each keep their own set of MCP/tool server processes alive. Also check file $(which node): an x86_64 Node under Rosetta on Apple Silicon (common with Intel Homebrew in /usr/local) slows every build and test; Next.js prints a warning about it at startup.Why
macOS compresses and swaps inactive pages aggressively, so a leaking or over-provisioned process can hold many GB while its RSS looks small. The cost then shows up as system-wide slowness rather than as one obviously large process.
Gotchas
- ps RSS understates compressed/swapped memory; use top's MEM column or the Memory column of Activity Monitor
- Freed swap does not drop instantly; pages of other processes stay in swap until touched
- Stopped containers with restart policy unless-stopped stay stopped after a Docker restart
- Restarting the dev server mid-run disrupts agents using it; do it between phases
Code Snippets
Find the real memory hogs on a swapping Mac
top -l 1 -o mem -n 30 -stats pid,ppid,mem,cmprs,time,command
sysctl -n vm.swapusage
docker stats --no-stream --format '{{.Name}} {{.MemUsage}} {{.CPUPerc}}'
lsof -p <vm_pid> | grep -Ei '\.(img|raw)' # which app owns a VM
file "$(command -v node)" # x86_64 under Rosetta?Context
Local development on a 16 GB Apple Silicon Mac with several long-running dev servers, a Docker Supabase stack and agent sessions open for days
Revisions (0)
No revisions yet.