DEV Community

vmitro
vmitro

Posted on

I profiled Claude Code so you don't have to, or How I Learned to Stop Worrying and Love the strace

My Laptop was running out of memory. A day like any other, when you think about it. But in particular, one culprit was throwing OOM Errors when loading previous sessions: Claude Code, Anthropic's CLI tool, casually consuming 1.6GB of RAM on a ~92 lines session. Idling. In it's own lane. Unbothered.

Anyway, I did what any reasonable person would do: go to GitHub Issues page and yell at clouds. Nah, nerdsniped to debug my own CLI/TUI tool that embeds Claude Code's TUI inside a tmux-like pane (along with Codex and Gemini) and uses heuristics and a bunch of headless xterm.js instances to try to mitigate the annoying Infiniscroll(TM) Bug plaguing the Anthropic's -- otherwise very capable and awesome -- tool, I attached strace to it.

The Setup

sudo strace -f -tt -p <Claude Code's PID> -e trace=read,openat,write,close > claude_fs_shennanigans.txt 2>&1
Enter fullscreen mode Exit fullscreen mode

Environment: WSL2, Linux 6.6.87, Claude Code 2.1.something. At the time of profiling, Claude was doing some git operations - checking out files, comparing commits... Nothing exotic, just trying to merge this one "HOLY SH*T IT WORKS DO NOT CHANGE ANYTHING WE'LL SLOWLY MERGE IT BACK INTO MAIN" branch bit by bit.

Finding #1: The Credentials

Claude Code reads its own .credentials.json file 1.9 times per second.

One point nine times per second. Try saying "BADGER BADGER BADGER BADGER BADGER" repeatedly; the chances are, Claude Code read your credentials already at the first furry friend. Twice.

/home/user/.claude/.credentials.json - 339 opens in 181 seconds
Enter fullscreen mode Exit fullscreen mode

The file is 433 bytes. It does not change. It sits there, on disk, being opened, read, and closed, every 0.5 seconds, in batches of six.

Opened, read, closed. BADGER BADGER BADGER -- that's one batch(er) already.

Perhaps it's checking if the credentials have spontaneously changed? Perhaps it doesn't trust its own memory? Does Claude even dream of electric sheep? We may never know.

Finding #2: The Changelog

Claude Code ships with a changelog. A reasonable thing to have. Me? I just tell Claude to commit a one-liner in Latin. But serious programmers actually do find it important to write and I enjoy reading me a conciselly written Changelog. Well, so does Claude Code, apparently. What's a bit less reasonable is reading it 18 times per second.

Eighteen times per second. That's whole lotta badgers.

~/.claude/cache/changelog.md - 70KB file
Read rate: ~18 reads/sec
Total: 683 reads, 5.5 MB in 38 seconds
Enter fullscreen mode Exit fullscreen mode

It's reading its own changelog. Repeatedly. During normal operation. The changelog does not update while the program is running. This is not a philosophical statement about the nature of change - it's just a static file. Well, at least it's not curl'ing it from their GitHub or anything, it reads it locally, and besides -- SSD reads aren't much of a problem, you should be worried about writes and luckily, Claude does somewhat better job at it (more about it later).

Finding #3: The Logs

Every log operation follows this pattern:

  1. openat() - open the log file
  2. write() - write 322 bytes
  3. close() - close the log file
  4. Repeat

The debug log alone: 70 open-write-close cycles to write 42KB.

| File            | Cycles | Bytes/Cycle |
|-----------------|--------|-------------|
| Debug log       | 63     | 610 B       |
| Statsig logs    | 39     | 1.27 KB     |
Enter fullscreen mode Exit fullscreen mode

I'm no Javascript or node.js programmer, my knowledge stops at the for loop and alert() but Claude told me that the fs module has a createWriteStream(). It exists (unless Claude hallucinated it). It's documented and everything, Claude wrote. Looking at the ugly camelCase through my innocent Python eyes I'd reckon it has something to do with writing stuff more efficiently, but I digress.

Finding #4: The Session File

Claude keeps a session file. Mine was 129MB. Claude reads the entire file. Then does it again. And again. And again. "Perhaps it changed," thought the machine, and so it read the file again. And again. and again. As if it tried to shake off a false memory.

Session JSONL: 129MB file, 3 opens in 42 seconds = 9 MB/s I/O
Debug log: 111MB file, 20 opens in 42 seconds = 53 MB/s I/O
Enter fullscreen mode Exit fullscreen mode

Combined estimated I/O from file re-reads: 64 MB/s.

To put this in perspective, that's faster than a spinning hard drive can physically read data. Fortunately, it's cached. Unfortunately, it's still being parsed by V8, which brings us to:

Finding #5: The Memory

I also traced mmap/munmap. V8 was allocating 256KB heap chunks at ~31 calls/second. In under a minute, it allocated 728MB of memory mappings.

This is the JavaScript garbage collector doing what garbage collectors do: collecting garbage. The garbage, in this case, probably being the parsed JSON from 100MB+ files that get re-read and re-parsed continuously. [BADGER INTENSIFIES]

The Full Picture

Problem Rate Impact
Credentials re-read 1.87/sec 339 opens for 433 bytes
Changelog re-read ~18/sec 5.5 MB read in 38 seconds
Debug log re-read 0.48/sec 53 MB/s I/O (111MB file)
Session re-read 0.07/sec 9 MB/s I/O (129MB file)
Open-write-close cycles ~1/sec 70 syscalls for 42KB

Recommendations (filed as GitHub issue #19459)

  1. Cache credentials in memory
  2. Cache the changelog (it's your own file)
  3. Keep log files open, use buffered writes
  4. Don't re-read 100MB files - stream or memory-map them
  5. Consider that JSON.parse() on a 129MB string might have consequences

The Profiler Scripts

I wrote some Python scripts to parse strace output:

  • strace_profiler.py - Aggregates read() calls by content type
  • strace_file_io_profiler.py - Calculates throughput from openat()
  • strace_write_profiler.py - Analyzes write() patterns
  • strace_fd_correlator.py - Maps file descriptors to file paths

Available on request or in the GitHub issue.

Conclusion

Claude Code is a good tool. I use it daily. It also reads its own changelog 18 times per second and opens its credentials file 339 times in three minutes. These are not mutually exclusive statements.

Philip K. Dick warned us about systems that cannot trust their own memories. Claude Code has apparently taken this warning seriously and now verifies its past approximately 18 times per second.


GitHub Issue: anthropics/claude-code#19459

© 2026. Provided for educational purposes. Reproduction in derivative content without permission is prohibited.``

Top comments (0)