Finding and Fixing Ghostty's Largest Memory Leak

· ai · Source ↗

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 munmap was 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