Finding and Fixing Ghostty's Largest Memory Leak
TLDR
- Ghostty’s PageList had a metadata desync bug causing non-standard mmap pages to never be freed; one user hit 37 GB after 10 days.
Key Takeaways
- The leak existed since Ghostty 1.0 but only surfaced at scale when Claude Code began generating frequent multi-codepoint grapheme output and heavy scrollback.
-
Root cause: during scrollback pruning, an optimization reused old pages by resetting metadata to standard size, but left the underlying oversized mmap allocation intact, so
munmapwas never called. - Fix: if the page being pruned is larger than standard size, destroy it properly and allocate a fresh standard-sized page from the pool instead of reusing it.
- Mitchell Hashimoto added macOS Mach kernel VM tags to PageList allocations, making it trivial to isolate the leak in Instruments and confirm the fix.
- A regression test covering the exact trigger conditions was added to CI; Ghostty already runs Valgrind on every GTK PR and uses leak-detecting Zig allocators in debug builds.
Why It Matters
- A single overlooked metadata reset in a hot-path optimization caused unbounded memory growth under a workload nobody predicted at design time.
- CLI tools that produce unusual terminal output (multi-codepoint graphemes, heavy primary-screen scrollback) can silently stress assumptions baked into terminal emulator internals.
- The fix ships in tip/nightly now and will be in the tagged 1.3 release; the community-provided reproduction by @grishy was the critical unlock for diagnosis.
Mitchell Hashimoto · 2026-01-10 · Read the original