Skip to content

【Zig 日报】发现并修复 Ghostty 最大的内存泄露问题 #300

@jiacai2050

Description

@jiacai2050

Finding and Fixing Ghostty's Largest Memory Leak – Mitchell Hashimoto 一文对终端模拟器 Ghostty 中一个长期存在的严重内存泄漏问题的回顾、诊断和修复过程。

1. 问题背景与现象

  • 现象: 几个月前,用户开始报告 Ghostty 会消耗“荒谬”的内存量,有用户报告在运行 10 天后消耗了 37 GB 内存。
  • 诊断难度: 内存泄漏从 Ghostty 1.0 版本开始就存在,但由于只有在特定条件下(例如处理大量多码点字形输出)才会大规模触发,因此很难被诊断出来。
  • 触发原因: 最近流行的 CLI 应用程序,特别是 Claude Code,产生了满足触发条件的输出,导致泄漏问题凸显。
  • 修复状态: 修复程序已找到并合并,已在 tip/nightly 版本中可用,并将包含在三月份发布的 1.3 版本中。

2. Ghostty 的内存管理机制 (PageList)

  • PageList: Ghostty 使用名为 PageList 的双向链表来存储终端内容。它由一系列内存“页”(Page)组成。
  • 内存分配: 为了效率,页面通常从内存池中分配(使用 mmap 进行预分配),这称为标准页面
  • 非标准页面: 当需要存储大量表情符号、样式或超链接时,标准页面不够用,此时会绕过内存池,直接使用 mmap 分配更大的、可变大小的非标准页面
  • 页面释放逻辑:
    • 如果页面大小 ≤ 标准大小,则返回内存池(等待重用)。
    • 如果页面大小 > 标准大小,则调用 munmap 彻底释放。
Image

3. 内存泄漏的根源:滚动回溯优化中的元数据错误

  • 滚动回溯优化: 为了避免频繁的内存分配/释放,当滚动回溯达到限制时,Ghostty 会将最旧的页面从列表头部移除,并将其作为最新的页面重新在列表尾部使用(重用)。
  • 漏洞 (The Bug): 在执行这个“重用最旧页面”的优化时,代码总是将页面的元数据大小重置为标准大小,但却没有调用 munmap 调整底层的实际内存分配
  • 泄漏发生: 当这个被重用过的、底层仍是非标准(大尺寸)分配的页面最终被释放时,释放逻辑会根据其元数据(标准尺寸)错误地判断它属于内存池,因此它被返回给内存池,而没有调用 munmap 释放底层的大块内存。这导致了经典的内存泄漏。

4. 修复方案

  • 修复理念: 永远不要重用非标准页面。
  • 具体措施: 在滚动回溯优化过程中,如果遇到一个非标准页面(即底层内存大于标准大小),则停止重用,而是调用 destroyNode (内部会调用 munmap) 将其彻底销毁,然后从内存池中分配一个全新的标准大小的页面来使用。

5. 调试与预防措施

  • 调试工具: 作者在修复过程中为 macOS 平台添加了 虚拟内存标签 (virtual memory tags) 支持,使得 Ghostty 的 PageList 内存分配在调试工具(如 Instruments)中带有特定标签,极大地简化了定位和验证修复的过程。
  • 防止未来泄漏的措施: Ghostty 项目已采取多项措施,包括在调试版本中使用泄漏检测分配器、在 CI 中运行 Valgrind、定期使用 macOS Instruments 检查,以及为本次修复添加了可重现此泄漏的单元测试。

Fix memory leak when pruning scrollback with non-standard pages by mitchellh · Pull Request #10251 · ghostty-org/ghostty

加入我们

Zig 中文社区是一个开放的组织,我们致力于推广 Zig 在中文群体中的使用,有多种方式可以参与进来:

  1. 供稿,分享自己使用 Zig 的心得
  2. 改进 ZigCC 组织下的开源项目
  3. 加入微信群Telegram 群组

Metadata

Metadata

Assignees

No one assigned

    Labels

    日报daily report

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions