Go 博客
Go GC:优先考虑低延迟和简洁性
设置
Go 正在构建一个垃圾收集器(GC),不仅是为了 2015 年,更是为了 2025 年及以后:一个 GC,它支持当今的软件开发,并随着新软件和硬件在未来十年不断发展而扩展。这样的未来将不再容忍“停止世界”(stop-the-world)的 GC 暂停,而这曾是 Go 等安全语言更广泛应用的障碍。
Go 1.5 是这个未来的第一个亮点,其 GC 延迟远低于我们一年前设定的 10 毫秒目标。我们在 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 选择一个灰色对象,将其标记为黑色,然后扫描它以查找指向其他对象的指针。当扫描发现指向白色对象的指针时,它会将该对象变为灰色。这个过程会重复进行,直到没有灰色对象为止。此时,白色对象被认为是不可达的,可以被重用。
所有这些都与应用程序(称为改变器)在收集器运行时更改指针的操作同时进行。因此,改变器必须维护一个不变量,即没有黑色对象指向白色对象,以免垃圾收集器丢失它已经访问过的堆部分中的某个对象。维护这个不变量是写屏障的职责,它是一个小的函数,当堆中的指针被修改时,改变器会运行它。Go 的写屏障会在指针指向的对象当前是白色时将其变为灰色,从而确保垃圾收集器最终会扫描它以查找指针。
决定何时完成查找所有灰色对象的工作是微妙的,并且如果我们要避免阻塞改变器,可能会很昂贵且复杂。为了保持简单,Go 1.5 会尽可能多地并行执行工作,然后短暂地停止世界(stop-the-world)以检查所有潜在的灰色对象来源。在这次最终的停止世界所需的时间和此 GC 所完成的总工作量之间找到最佳平衡点是 Go 1.6 的一个主要交付成果。
当然,细节决定成败。我们何时开始 GC 周期?我们使用什么指标来做这个决定?GC 应如何与 Go 调度程序交互?我们如何暂停改变器线程足够长的时间来扫描其堆栈?我们如何表示白色、灰色和黑色,以便我们能够有效地查找和扫描灰色对象?我们如何知道根在哪里?我们如何知道对象中的指针在哪里?我们如何最小化内存碎片?我们如何处理缓存性能问题?堆应该有多大?等等,有些与分配有关,有些与查找可达对象有关,有些与调度有关,但很多都与性能有关。这些领域的低级讨论超出了本博文的范围。
从更高层次来看,解决性能问题的一种方法是添加 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 发布
博客索引