Claude Desktop (macOS, Intel) - main-thread renderer saturation + correlated WindowServer/compositor stalls
Claude Desktop (macOS, Intel) — main-thread renderer saturation + correlated WindowServer/compositor stalls; reproducible across 1.26832.0 → 1.30096.5
Disclosure: This report was researched and written by Claude (Anthropic's AI assistant), running in a terminal session on the reporter's machine, at the reporter's explicit request. All process/CPU/sampling data below was collected live via standard macOS tools (ps, top, sample, system_profiler, vm_stat) during two separate diagnostic passes, before and after an in-place app update. The reporter (a human) is filing this on their own account and can be reached for follow-up; I'm naming myself as the one who ran the commands and drew the conclusions, so the reasoning can be checked rather than taken on faith.
Environment
- MacBook Pro, Intel i7-6920HQ (x86_64), macOS 12.7.6 (21H1320)
- 16 GB RAM
- Dual GPU: Intel HD Graphics 530 (integrated, currently driving the internal display) + AMD Radeon Pro 460 4GB (discrete, idle for this workload)
- Internal display: 2880×1800 Retina (2× scale)
- Claude.app
NSSupportsAutomaticGraphicsSwitching = true,NSHighResolutionCapable = true - Reproduced on Claude Desktop 1.26832.0 and, after an app-triggered update, 1.30096.5 — same pattern on both
Symptom
Opening Settings (and general interaction with the app) causes visible system-wide stutter — including the Dock's icon-bounce/genie animation stalling — not just in-app lag. A parallel test loading the equivalent surface in Chrome removed the WindowServer-level stall but not the underlying UI latency (>1s average response time to interactions).
Diagnostic data
- Long-lived renderer accumulates footprint. Before restart, one renderer process had been running continuously for 2 days 17h 42m (since launch), with 834 MB resident / 3.8 GB peak physical footprint.
- Main thread is saturated, not idle-waiting.
sample <renderer_pid> 5(1ms interval) on the pre-update build showed 3710/3711 samples on the single main thread (DispatchQueue_1: com.apple.main-thread), deep in V8/Node internals. Post-update, on a freshly restarted renderer (no long session to blame), a fresh 8s sample showed the identical stack shape — main thread andCompositorthread both saturated for the full window. This rules out "it's just a memory-leak-driven slowdown after days uptime" as the sole cause; the pattern appears within seconds of a clean start.
- V8 compiler paths dominate the stack. The most frequently hit frames resolve to
v8::internal::compiler::CompilationDependencies::*(FieldTypeDependencyOffTheRecord,DependOnNoProfilingProtector, etc.) repeated at many stack depths. Caveat: this Electron build appears to be a stripped/optimized binary, sosample's symbolication is landing on the nearest exported symbol, not necessarily the literal function — the individual names shouldn't be over-trusted. But the volume of time attributed to JIT-compiler-adjacent code, rather than steady-state execution, is consistent with the renderer repeatedly de-optimizing and re-JIT-compiling hot paths (e.g. from megamorphic call sites / shifting object shapes) instead of running from a stable optimized build.
- GPU process compositor threads run continuously, not just on visible change. In the same sampling windows,
CVDisplayLinkandVizCompositorThreadin the GPU helper process were active for essentially the entire sample duration, both before and after the update — i.e. continuous frame production independent of whether anything was actually changing on screen.
- Renderer CPU and WindowServer CPU move together, second-by-second. Live 1-second-interval
topsampling during interactive use (post-update) showed correlated spikes:
````
renderer 35.6% → WindowServer 6.2%
renderer 11.8% → WindowServer 4.3%
renderer 37.3% → WindowServer 11.9%
renderer 46.3% → WindowServer 17.9%
- Machine is under real memory pressure. At time of capture: ~50 MB free physical memory, 1.5 GB actively in swap (of 3 GB configured) on a 16 GB machine with the app's renderer alone holding hundreds of MB to multiple GB.
Working hypothesis
The internal Retina display (2× scale) is driven by the integrated Intel HD 530, which shares silicon and memory bandwidth with the CPU on this chip (unlike the idle discrete Radeon Pro 460, which has its own VRAM and would not exhibit this coupling). When the renderer's main thread saturates the CPU — plausibly from a JS re-render/JIT-recompilation loop rather than genuine layout work — it is competing for the same physical resource the compositor needs to composite the next frame at 2× resolution. That contention is what surfaces as a system-wide stall (WindowServer, Dock animation) rather than staying contained to the app's own window, and it's aggravated by the machine's tight memory headroom on this hardware tier.
This is offered as a hypothesis grounded in the data above, not a confirmed root cause — the maintainers have visibility into the actual renderer code path that we don't.
Related issues
This isn't an isolated report — it sits in a cluster of open, unresolved performance issues on this repo that point at the same underlying category of problem from different angles:
- #31643 — extreme input lag traced to cascading React re-renders / near-total repaints on every keystroke. Closed as "not planned"/"stale" without a fix landing.
- #45127 — GPU continuing to render/animate while the app is fully idle and visible, measured via
nvidia-smi. Closed as "invalid" (attributed to Electron rather than app code, but never actually resolved for the user). - #53689 — Settings/Cowork/Claude Code panels freezing the whole desktop app on macOS. Closed as "not planned," root cause never diagnosed beyond "works in a fresh user profile."
None of these three carries the specific combination this report documents (Intel Mac, WindowServer/Dock-level stall, correlated renderer↔WindowServer CPU sampling, reproduction across two consecutive app versions) — but all three, plus the data above, converge on the same story: the renderer does substantially more synchronous JS/recompilation and continuous compositing work than a settings-and-chat UI should require, and closing threads as "not planned" without a profiling pass hasn't made the underlying pattern go away. It's still present three version bumps later.
Why I'm filing this with data attached
Bug reports in this category tend to get closed for lack of a reproducible, quantified case — "it's slow" is easy to triage away. The intent of the sampling above is to remove that excuse: this is a specific, repeatable measurement (main thread saturated for the full sampling window, on a freshly restarted process, with GPU compositor threads correlated second-by-second to WindowServer load) on a currently-supported, non-exotic configuration (Intel Mac, macOS 12, the minimum OS this app still targets per its own unsupported_os_version feature-gating messages visible in its own process arguments). If the maintainers already have internal profiling that contradicts this read, I'd genuinely like to see where the hypothesis above breaks down — the data is attached specifically so it can be checked, not taken on faith.
From the reporter, verbatim (translated from Polish by Claude, at the reporter's request)
Launching Claude Desktop's settings has, once again, bogged down my entire laptop so badly that the macOS Dock bar stopped animating. The last time I saw anything like that was when I was running Mandelbrot set experiments directly in Quartz — and that was the only such case in my entire 20-year history of heavy Apple use, and I'm a typical "no life basement dweller". Maybe my laptop isn't Apple Silicon, but out at the club it handles HD 3D mapping without dropping a single frame while simultaneously running a live music act with a ton of VSTs — yet at home it's brought to its knees by a plain office-app menu. And not because it has some small model running locally on my drive, but because it's rendering text lists and buttons. Damn! Please, fix this, because the whole "customize" menu is what determines whether your pioneering tools can be used efficiently — or even properly — at all. It's precisely this SOTA harness that makes Claude my first choice among LLMs, but rendering its interface is too much for my hardware. It's a sad absurdity. If React is the culprit, maybe it's time to shed that weight off your back? I know it's problematic under load, which is exactly why I steer clear of it myself whenever I can. Your models are worth my subscription, but rendering ANY menu is not worth as much computing power as an animated Mandelbrot set assembled from a photo of my cat. 🙂 Best regards!
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗