1 ポイント 投稿者 GN⁺ 2026-01-11 | 1件のコメント | WhatsAppで共有
  • Ghosttyターミナルエミュレータで長時間実行時に数十GBのメモリを占有する深刻なリーク現象が発見された
  • 問題の原因は、PageList構造体の非標準メモリページ再利用ロジックmunmapが呼ばれず、解放されないメモリが蓄積していたこと
  • Claude Code CLIが複数コードポイントのグラフ出力を頻繁に生成することで、非標準ページの使用頻度が高まり、リークが大規模に表面化した
  • 修正は非標準ページを再利用せず即座に解放するよう変更され、macOSのVMタグ機能を活用してリーク追跡と検証が行われた
  • この修正はGhosttyの最大のリーク問題の解決と評価されており、今後のリリース(1.3)に含まれる予定

Ghosttyのメモリリーク概要

  • 一部のユーザーが、Ghosttyが長時間実行後に37GB以上のメモリを使用する事例を報告
    • リークは少なくともバージョン1.0から存在しており、最近のCLIアプリが特定条件を満たして問題を露呈させた
  • 修正はすでにGitHubにマージされており、nightlyビルドと1.3正式リリースに含まれる予定

PageList構造とメモリ管理方式

  • Ghosttyはターミナル内容を保存するため、PageListという双方向リンクリスト構造を使用している
    • 各ページは文字、スタイル、ハイパーリンクなどのデータを含む
  • ページはmmapで割り当てられ、**標準サイズページプール(pool)**を通じて再利用される
    • 標準サイズ以下のページはプールに返却
    • 非標準サイズのページは直接munmapで解放しなければならない
  • この構造自体は正常だが、最適化ロジックのバグによってリークが発生した

Scrollback最適化とバグ発生原因

  • Ghosttyはscrollback-limitを超えると、最も古いページを再利用する最適化を行う
    • 新しいページを割り当てずポインタだけを調整して性能を向上
  • 問題はこの過程で、非標準ページのメタデータだけを標準サイズに変更し、実際のメモリはそのままだった点にある
    • その後の解放時に標準ページと誤認され、munmapが呼ばれない
  • その結果、非標準ページが解放されないまま蓄積し、長時間実行時に大規模なメモリリークが発生した

Claude Codeとリークの大規模露出

  • Claude Code CLIが複数コードポイントのグラフ出力を頻繁に生成し、非標準ページの使用頻度が増加
    • さらにスクロールバック出力も多く、リークが急速に蓄積した
  • Ghosttyの設計上、非標準ページはまれにしか発生しないはずだが、Claude Codeの特性によってリークが大量に再現された
  • 開発者は、このバグはClaude Codeの問題ではなく、Ghostty内部ロジックの欠陥であると明示している

修正内容

  • 解決策は**非標準ページを再利用せず即座に解放(munmap)**する方式
    • スクロールバック中に非標準ページを見つけた場合、新しい標準ページをプールから再割り当てする
  • 一部ユーザーは非標準ページ再利用戦略を提案したが、現時点では単純で安全な修正が優先して適用された
  • 修正コード例:
    if (first.data.memory.len > std_size) {
        self.destroyNode(first);
        break :prune;
    }
    

VMタグを活用したリーク追跡

  • macOSのMachカーネルVMタグ機能を使い、PageListメモリ割り当てに特定タグを付与
    • デバッグ時にGhosttyのメモリ領域を明確に識別可能
    • リーク原因の追跡と修正検証に大きく役立った
  • この機能により、PageList関連メモリが解放されたかどうかを視覚的に確認できる

Ghosttyのメモリリーク防止体制

  • Ghosttyはさまざまな方法でリークを検知・防止している
    • デバッグビルドと単体テストでZigのリーク検知アロケータを使用
    • CIでvalgrindによる全体テストを実施
    • macOS InstrumentsでSwiftコードのリーク検査
    • GTK関連PRはValgrind GUIテストで検証
  • 今回のリークは特定条件でのみ発生したため、既存テストでは再現されなかった
    • 新しいテストケースが追加され、回帰防止が確保された

結論

  • 今回の問題は、Ghosttyでこれまでで最大規模のメモリリークと確認された事例
  • 修正後もユーザー報告と再現テストを通じて継続的に監視する予定
  • コミュニティによる診断データと再現事例の提供が問題解決に決定的な役割を果たした
  • 再現可能な環境の確保がメモリリーク解決の核心であることを強調している

1件のコメント

 
GN⁺ 2026-01-11
Hacker News の意見
  • 本当にうれしいニュース。問題解決に関わったすべての人に拍手を送りたい
    先週すでにこのスレッドでも言及されていたバグだった
    Claude Code がこのバグをより多くのユーザーの目に触れさせるきっかけになったようだが、私のように Claude Code をまったく使っていなくても同じ問題に遭遇した人もいた
    ページが「非標準(non-standard)」に分類される基準は、思ったほど白黒はっきりしたものではない
    また、scrollback-limit = 0 のような設定を使っていた人には、リークがより頻繁に発生していた可能性もあると思う
    修正方法によっては不要に非標準ページを削除して再生成してしまうこともありそうで、すでに非標準になっている古いページを再利用できなかったのか、という惜しさはある

    • その点はブログ記事ですでに触れられていた
      PageList の動作方式は以前から同じで、バグがあったときも容量調整中に誤ったサイズを見ていただけだった
      体感できるような性能変化はないはず
      提案された代替案も検討したが、現在のアプローチはベンチマークデータで十分に裏づけられている
      私も考えを変える余地はあるが、今回は世界観そのものを変えるよりリーク修正に集中した
    • ベータ段階で問題を見つけて報告できたのは幸運だった
      実際、segfault を引き起こす再現可能なバグだった
    • ちなみに、Claude Code のおかげで CLI が再び魅力的に感じられる
      この20年で何よりも CLI を新鮮に見せてくれた
    • メモリリーク関連のスレッドはこちら
  • 素晴らしい記事だった。Ghostty を作ってくれた mitchellh に感謝
    去年乗り換えたが、一度も後悔していない
    ただ、修正が数か月後の機能リリースに含まれるというのは少し意外だった
    バグ修正リリースに入るものだと思っていた

    • すでに最新の nightly build に含まれている
  • ページの話が出た瞬間に「なるほど、メモリプーリングか」と思い、「リングバッファだな」と予想したが、やはり scrollback の再利用だった
    バグの場所もすぐ見当がついた —— ページメモリを正しく解放していない箇所だった
    メモリアラインメントの図も見事だった
    新しいことを試すたびにリークの可能性が生まれると改めて思い知らされる

  • 今週 Ghostty に移行したが、ターミナル UI アプリの開発中に OOM クラッシュ を経験した
    タブバーで UTF8 アイコンを使う構成だったが、ターミナルのサイズを変更するとすぐにクラッシュした
    再現が簡単だったのでバグレポートを準備していたが、ブログ記事で説明されている問題と非常によく似ているように見える
    解決されることを期待している

  • @mitchellh に質問した — メモリ可視化はどのツールで作ったのか、そしてウェブサイトがモバイルでもよく動いていたので、スタック構成が気になる

    • Opus 4.5 で生成した静的な HTML/CSS を使った
      可視化用コードは使い捨てなので、品質よりも正確性だけを確認した
      ブログ記事ごとに名前空間を分けており、再利用はしていない
      実装が妙なこと(たとえばビットコインのマイニングや秘密情報の流出など)をしないかだけ確認した
      核心は情報を伝えることであり、こうした図は内容をずっと理解しやすくしてくれる
  • Ghostty の開発はずっと追っている
    少しオーバーエンジニアリングっぽさはあるが、こういうバグのポストモーテムはクラフトマンシップを愛する人にとって非常に価値のある資料だ

    • どのあたりをオーバーエンジニアリングだと感じたのか気になる
  • Rust ベースのターミナルなら、こういう実装を性能低下なしでどう処理するのか気になる

  • Ghostty やターミナルエミュレータに詳しくない立場でも理解しやすい記事だった
    とっつきやすく親切な説明が印象的だった

  • 再現可能なバグレポートの重要性を改めて感じた

  • 誰かが「Rust を使っていればこんなことは起きなかった」と言い出すのを待っている

    • かなり長く待つことになりそうだ
      Rust は**「メモリリーク安全性(leak safety)」を言語レベルで保証していない
      安全な Rust コードでもメモリリークは起こせる —— ただし、それは安全性の問題ではない
      標準 API にも Box::leak のように明示的にリークを許すものがある
      Rust は単に
      意図しないリーク**を起こしにくくするだけで、完全に防ぐわけではない