# Why Is Claude Code So Slow, Hanging or Eating Memory? Start With the Silent Failures

> High CPU, frozen commands and missing search results usually trace to a handful of specific causes — a compaction loop, a bundled ripgrep that won't run, or WSL quietly returning fewer matches while claude doctor reports everything as OK.

By Tahir Nazir · Published 2026-08-16 · Updated 2026-10-28
Canonical: https://www.its-tahir.com/blog/why-claude-code-is-slow-hanging-or-eating-memory

**If Claude Code is slow, hanging or eating memory, the causes that cost the most time are the silent ones: WSL search quietly returning fewer matches, a bundled ripgrep that won't run while `claude doctor` says OK, and a compaction loop that keeps refilling the context. Check those before anything else.**

If Claude Code is slow, hanging, or eating memory, the useful first move is `/doctor` — it checks your installation, settings, extensions and context usage, and proposes fixes it can apply after you confirm. If it won't start at all, run `claude doctor` from your shell instead.

But the causes worth knowing are the ones that produce **no error at all**. Slowness that announces itself is easy; what costs you a day is the failure that reports everything as fine.

## The silent one: search quietly returns fewer results on WSL

This is the failure I'd check first if you're on Windows, because nothing tells you it's happening.

Working across file systems on WSL carries a disk read performance penalty, and the practical effect is that searches **return fewer matches than they should**. Search still works. It just misses things.

And the part that makes it genuinely nasty:

> `claude doctor` shows Search as OK in this case.

So you get a green check, an agent that seems to not understand your codebase, and no error anywhere. Three fixes, in order of effectiveness:

1. **Move the project onto the Linux filesystem** — `/home/` rather than `/mnt/c/`. This removes the penalty rather than working around it.
2. **Run natively on Windows** instead of through WSL, for better filesystem performance.
3. **Narrow your searches** — "Search for JWT validation logic in the auth-service package" instead of a repo-wide sweep.

## The other silent one: bundled ripgrep won't run

If the Search tool, `@file` mentions, custom agents or custom skills aren't finding files, the bundled `ripgrep` binary may not run on your system at all.

Install your platform's package:

```bash
# macOS
brew install ripgrep

# Ubuntu/Debian
sudo apt install ripgrep

# Windows
winget install BurntSushi.ripgrep.MSVC
```

Then point the CLI at it, either in your shell environment or the `env` block of `settings.json`:

```json
{
  "env": {
    "USE_BUILTIN_RIPGREP": "0"
  }
}
```

**Verify it actually took effect** rather than assuming: run `claude doctor` and check that the Search line shows the path to your system ripgrep instead of `OK (bundled)`.

## When it keeps compacting

A session that compacts again and again is slow in the worst way: each compaction can take a minute or more, and the work stalls between them. If it ends with `Autocompact is thrashing: the context refilled to the limit within 3 turns of the previous compact, 3 times in a row`, compaction worked but something refilled the window straight away, so Claude Code stopped retrying.

Run `/context`. If the **Messages** row is the largest, a file or tool output is refilling it: have Claude read big files in chunks, or move that work to a subagent. If the rows above it are larger together, what loads at startup (CLAUDE.md, rules, MCP tools) leaves too little room. The full diagnosis of ["Autocompact is thrashing" and the other reasons Claude Code keeps compacting](/blog/claude-code-keeps-compacting) covers compactions that only look early and the auto-compact window settings too.

A related gotcha: `/compact` can return `Not enough messages to compact.` **even when your context is full** — that happens when a single large paste filled it, so there aren't enough turns to summarize. And if the message you came back to was `Compacted while idle, before the prompt cache expired`, that's not thrashing at all — it's [idle compaction, a cost-saving feature with its own off switch](/blog/claude-code-compacted-while-idle).

## High CPU or memory

Work through these before reaching for diagnostics:

- **`/compact` regularly** to keep context size down.
- **Restart between major tasks.** Long-lived sessions accumulate.
- **Add large build directories to `.gitignore`.**
- **Restart with `claude --safe-mode`.** This is the one people skip, and it's the highest-signal step: it disables every customization for the session. If usage drops, a plugin, MCP server or hook is your culprit, and you can bisect from a clean configuration.

If memory stays high after all that, `/heapdump` writes a heap snapshot and a diagnostics file to your Desktop, and prints a summary showing resident set size, JS heap, array buffers and unaccounted native memory, plus leak indicators like a high growth rate or an unusual number of open handles. The command doesn't appear in the command menu — type it in full.

⚠️ **Do not attach the `.heapsnapshot` to a public issue.** It contains every string in the process, which means your full conversation *and your credentials*. If you're reporting a bug, attach only the `-diagnostics.json`, which carries the statistics and no conversation content.

The summary also tells you whether memory is in the JS heap — which the snapshot captures, and which you can inspect in Chrome DevTools under Memory → Load, sorted by retained size — or in native memory, which it doesn't capture at all.

## Hangs, and the fear of losing your session

If the CLI stops responding: press **Ctrl+C** to cancel the current operation. If it stays unresponsive, close the terminal.

**Restarting doesn't lose your conversation.** Run `claude --resume` in the same directory and pick the session back up. People tolerate a frozen terminal for far too long because they assume otherwise.

## Two display problems that look like bugs

Slow rendering is one thing; **garbled or corrupted text** in the VS Code, Cursor or Devin Desktop integrated terminal is another — characters rendering as boxes, smears or wrong glyphs — is almost always the terminal's GPU renderer. Run `/terminal-setup` to switch `terminal.integrated.gpuAcceleration` to `"off"`, then reload the window.

**A truncated table** isn't data loss. A Markdown table over 200 rows renders the first 200 followed by `… N more rows not shown`. Only the *display* is capped — the full table is still in the conversation, and `/copy` copies every row. For anything genuinely large, ask Claude to write it to a file instead.

## When it's cost, not performance

Being slow and being expensive get conflated, and they have different fixes. If the symptom is your plan limit disappearing rather than the CLI feeling sluggish, the causes are different — long context re-sent on every turn, prompt cache expiry, idle sessions still spending. I covered those separately in [why Claude Code burns tokens while you're not even using it](/blog/why-claude-code-uses-so-many-tokens).

And if the symptom is specifically that tools aren't available rather than slow, that's usually configuration rather than performance — see [MCP server not showing up in Claude Code](/blog/mcp-server-not-showing-up-in-claude-code).

**Key takeaways**

- On WSL, search silently returns fewer matches when working across filesystems — and claude doctor still reports Search as OK. Move the project to /home/ rather than /mnt/c/.
- If files aren't being found at all, the bundled ripgrep may not run. Install your own and set USE_BUILTIN_RIPGREP=0, then confirm the path in claude doctor.
- A session that keeps compacting is slow because each compaction stalls the work. Run /context to see whether a file or what loads at startup keeps refilling the window.
- claude --safe-mode disables every customization for one session — the fastest way to prove whether a plugin, MCP server or hook is responsible.
- Restarting never loses your conversation. Ctrl+C, then claude --resume in the same directory.

The pattern across all of these: the loud problems are the easy ones. A hang tells you it's hung. What costs you a day is search quietly returning half the matches while every diagnostic reports OK — so when the agent seems to have stopped understanding your codebase, check the silent failures before you rewrite your `CLAUDE.md`.

If you're seeing an actual error message rather than slowness, [the full list of Claude Code errors and fixes](/blog/claude-code-troubleshooting) will match it.

I run Claude Code on Windows daily, which is where most of these bite hardest; [ContextZero](/work/contextzero) came out of the adjacent problem of controlling what these tools know about a project in the first place.

## FAQ

### Why is Claude Code so slow?

Check the silent causes first. On WSL, searching across the Windows filesystem is slow and returns fewer matches while claude doctor still reports Search as OK. A bundled ripgrep that won't run breaks file search. A long session can keep compacting, which costs a minute or more each time. For high CPU or memory, compact or restart between tasks and try claude --safe-mode to rule out a plugin, MCP server or hook.

### Why is Claude Code not finding files that definitely exist?

The bundled ripgrep binary may not run on your system. Install your platform's ripgrep package and set USE_BUILTIN_RIPGREP to 0, then confirm with claude doctor that the Search line shows your system ripgrep path instead of OK (bundled). On WSL there is a second cause: searching across the Windows filesystem returns fewer matches than expected, and claude doctor still reports Search as OK.

### Will restarting Claude Code lose my conversation?

No. If a command hangs, press Ctrl+C first; if it stays unresponsive, close the terminal. Run claude --resume in the same directory afterwards to pick the session back up.

### How do I tell whether a plugin or MCP server is causing high resource usage?

Restart with claude --safe-mode, which disables every customization for that session. If usage drops, one of your plugins, MCP servers or hooks is responsible, and you can bisect from there against a clean configuration.

## Sources

- [Troubleshooting — Claude Code docs](https://code.claude.com/docs/en/troubleshooting)
- [Manage costs effectively — Claude Code docs](https://code.claude.com/docs/en/costs)
- [Working across file systems — WSL documentation](https://learn.microsoft.com/en-us/windows/wsl/filesystems)
