Go 博客

Go GC:优先考虑低延迟和简便性

Richard Hudson
2015 年 8 月 31 日

设置

Go 正在构建一个不仅面向 2015 年,也面向 2025 年及更远的垃圾收集器(GC):一个支持当今软件开发并能够随着未来十年新软件和硬件的发展而扩展的 GC。这样的未来没有停顿世界 GC 暂停的容身之处,这一直是更广泛地使用 Go 等安全可靠语言的障碍。

Go 1.5 是这个未来的第一瞥,它实现了远低于我们一年前设定的 10 毫秒目标的 GC 延迟。我们在 Gophercon 上的演讲 中展示了一些令人印象深刻的数据。延迟改进引起了很多关注;Robin Verlangen 的博客文章 每天数十亿次请求遇见 Go 1.5 用端到端的结果验证了我们的方向。我们也特别喜欢 Alan Shreve 的生产服务器图表 以及他“神圣的 85% 减少”的评论。

如今 16GB 的 RAM 价值 100 美元,CPU 拥有许多核心,每个核心都有多个硬件线程。十年后,这些硬件会显得过时,但今天在 Go 中构建的软件需要扩展以满足不断增长的需求和下一个重大突破。鉴于硬件将提供提高吞吐量的能力,Go 的垃圾收集器正在被设计为偏向低延迟,并通过一个旋钮进行调整。Go 1.5 是沿着这条道路迈出的第一步,而这些第一步将永远影响 Go 及其最适合支持的应用程序。这篇博文概述了我们为 Go 1.5 收集器所做的工作。

装饰

为了创建一个面向未来十年的垃圾收集器,我们转向了数十年前的一种算法。Go 的新垃圾收集器是一个并发的、三色的、标记清除收集器,这个想法最初由 Dijkstra 在 1978 年提出。这与当今大多数“企业级”垃圾收集器有明显的区别,我们认为它非常适合现代硬件的特性以及现代软件的延迟要求。

在三色收集器中,每个对象要么是白色、灰色或黑色,我们将堆视为连接对象的图形。在 GC 周期的开始,所有对象都是白色的。GC 会访问所有,这些根是应用程序可以直接访问的对象,例如全局变量和堆栈上的对象,并将它们涂成灰色。然后 GC 选择一个灰色对象,将其涂成黑色,然后扫描它以查找指向其他对象的指针。当此扫描找到指向白色对象的指针时,它会将该对象涂成灰色。此过程重复,直到不再有灰色对象。此时,已知白色对象是无法访问的,可以重复使用。

所有这些都与应用程序并发发生,应用程序被称为mutator,在收集器运行时会更改指针。因此,mutator 必须维护一个不变性,即没有黑色对象指向白色对象,以免垃圾收集器丢失对已访问堆部分中安装对象的跟踪。维护这种不变性是写入屏障的工作,写入屏障是一个由 mutator 在修改堆中的指针时运行的小函数。Go 的写入屏障会将现在可访问的对象涂成灰色(如果它当前是白色的),确保垃圾收集器最终会扫描它以查找指针。

确定何时完成查找所有灰色对象的工作非常微妙,如果我们想要避免阻塞 mutator,它可能非常昂贵且复杂。为了保持简单性,Go 1.5 会尽可能并发地进行工作,然后短暂地停止世界以检查所有潜在的灰色对象来源。找到这种最终停止世界所需的时间与该 GC 完成的工作总量之间的最佳平衡点是 Go 1.6 的主要成果。

当然,问题在于细节。我们何时开始一个 GC 周期?我们使用哪些指标来做出这个决定?GC 如何与 Go 调度器交互?我们如何暂停一个 mutator 线程足够长的时间来扫描它的堆栈?我们如何表示白色、灰色和黑色,以便我们可以有效地找到和扫描灰色对象?我们如何知道根在哪里?我们如何知道对象中的指针位于哪里?我们如何最大程度地减少内存碎片?我们如何处理缓存性能问题?堆应该有多大?等等,有些与分配有关,有些与查找可访问的对象有关,有些与调度有关,但很多与性能有关。有关这些领域的每个领域的低级讨论超出了这篇博文的范围。

在更高级别上,解决性能问题的一种方法是添加 GC 旋钮,每个性能问题对应一个旋钮。然后,程序员可以转动这些旋钮,寻找适合其应用程序的设置。缺点是,在十年中每年添加一两个新旋钮后,你最终会得到 GC 旋钮转动员就业法。Go 不会走这条路。相反,我们提供一个名为 GOGC 的单个旋钮。该值控制堆的总大小相对于可访问对象的大小。默认值 100 表示堆的总大小现在比上次收集后可访问对象的大小大 100%(即两倍)。200 表示堆的总大小比可访问对象的大小大 200%(即三倍)。如果你想减少在 GC 上花费的总时间,请增加 GOGC。如果你想用更多 GC 时间换取更少的内存,请降低 GOGC。

更重要的是,随着下一代硬件的 RAM 翻倍,只需将 GOGC 翻倍即可将 GC 周期的次数减半。另一方面,由于 GOGC 基于可访问对象的大小,通过将可访问对象的数量翻倍来使负载翻倍则不需要重新调整。应用程序只需扩展即可。此外,由于不受对数十个旋钮的持续支持的束缚,运行时团队可以专注于根据来自真实客户应用程序的反馈来改进运行时。

关键点

Go 1.5 的 GC 开启了一个未来,在未来,停顿世界暂停不再是转向安全可靠语言的障碍。这是一个应用程序随着硬件无缝扩展的未来,随着硬件变得更加强大,GC 不会成为改进、更可扩展软件的障碍。这是未来十年及更远的理想位置。有关 1.5 GC 的更多详细信息以及我们如何消除延迟问题,请参阅 Go GC:延迟问题已解决演示文稿幻灯片

下一篇文章:Golang UK 2015
上一篇文章:Go 1.5 已发布
博客索引