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 彻底释放。
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 在中文群体中的使用,有多种方式可以参与进来:
- 供稿,分享自己使用 Zig 的心得
- 改进 ZigCC 组织下的开源项目
- 加入微信群、Telegram 群组
Finding and Fixing Ghostty's Largest Memory Leak – Mitchell Hashimoto 一文对终端模拟器 Ghostty 中一个长期存在的严重内存泄漏问题的回顾、诊断和修复过程。
1. 问题背景与现象
2. Ghostty 的内存管理机制 (PageList)
PageList的双向链表来存储终端内容。它由一系列内存“页”(Page)组成。mmap进行预分配),这称为标准页面。mmap分配更大的、可变大小的非标准页面。munmap彻底释放。3. 内存泄漏的根源:滚动回溯优化中的元数据错误
munmap调整底层的实际内存分配。munmap释放底层的大块内存。这导致了经典的内存泄漏。4. 修复方案
destroyNode(内部会调用munmap) 将其彻底销毁,然后从内存池中分配一个全新的标准大小的页面来使用。5. 调试与预防措施
PageList内存分配在调试工具(如 Instruments)中带有特定标签,极大地简化了定位和验证修复的过程。加入我们
Zig 中文社区是一个开放的组织,我们致力于推广 Zig 在中文群体中的使用,有多种方式可以参与进来: