为什么 Go 在 GC 时 STW 的时间很短

问答为什么 Go 在 GC 时 STW 的时间很短
王利头 管理员 asked 7 月 ago
3 个回答
Mark Owen 管理员 answered 7 月 ago

作为一名 Go 开发者,我经常被问到有关垃圾回收 (GC) 的问题,尤其是为什么 Go 的 GC 可以在不中断应用程序的情况下进行,而其他语言的 GC 则会导致停顿。今天,我就来深入探讨一下这个话题,解释 Go 是如何实现低停顿 GC 的。

背景:什么是 STW?

STW(停止世界)是指 GC 过程中应用程序执行被暂停的时间段。在传统的 GC 实现中,STW 是不可避免的,因为 GC 需要扫描整个堆并确定哪些对象仍在使用。这个过程可能会花费很长时间,尤其是对于大型应用程序。

Go 的渐进式 GC

与传统 GC 不同,Go 使用了一种称为渐进式 GC 的方法。正如其名称所示,渐进式 GC 将 GC 过程分解为较小的、可以并行执行的任务。这些任务可以在应用程序执行的同时在后台运行,从而避免了 STW。

Go 的三色标记算法

渐进式 GC 的核心是三色标记算法。该算法将对象分为三类:

  • 白色:未标记的对象。
  • 灰色:已开始标记但尚未完成的对象。
  • 黑色:已完全标记的对象。

GC 线程从根对象(如全局变量或栈上的局部变量)开始扫描堆。它标记根对象为灰色,然后递归地标记这些对象引用的任何其他对象为灰色。

并发标记

标记阶段是 Go GC 的关键部分。为了实现并发性,Go 使用了多个称为标记器 Goroutine。这些标记器同时运行,并发标记堆中的对象。每个标记器都维护一个本地缓存,用于跟踪已标记和未标记的对象。

清除阶段

一旦所有对象都已标记,GC 线程就会进行清除阶段。在此阶段,它遍历堆并回收所有仍为白色的对象(即未被引用)。由于所有灰色和黑色对象都已标记为仍被使用,因此不需要 STW。

其他优化

除了渐进式 GC 和三色标记算法之外,Go 还实施了其他优化来减少 STW:

  • 逃逸分析:该分析器可以识别不会逃逸到堆的临时变量。这些变量可以存储在栈上,从而减少堆分配并且使 GC 更快。
  • 内存分段:Go 将堆划分为不同的段,例如年轻代和老年代。年轻代中的对象更有可能被回收,因此可以更频繁地进行清理。
  • 并发回收:除了并发标记之外,Go 的 GC 线程也可以并发回收对象。这进一步减少了 STW 时间。

结论

通过采用渐进式 GC、三色标记算法以及其他优化,Go 能够在不中断应用程序的情况下执行 GC。这使得 Go 非常适合对延迟敏感的应用程序和高并发场景。如果您正在寻找一种具有快速 GC 和低停顿时间的语言,那么 Go 绝对值得考虑。

seoer788 管理员 answered 7 月 ago

作为一名 Go 开发人员,我经常被问到一个问题:“为什么 Go 在进行垃圾回收 (GC) 时,停止整个世界 (STW) 的时间这么短?”这是个好问题,因为 STW 可能会对应用程序性能产生重大影响。让我们深入了解一下 Go 是如何实现短 STW 时间的。

什么是 STW?

在讨论 Go 的 GC 之前,我们先来了解一下 STW。STW 是一个术语,用于描述在 GC 过程中应用程序执行暂停的状态。这是因为 GC 需要扫描内存并找出不再被程序使用的对象,而这需要停止所有并发活动。

Go 的 GC 算法

Go 使用了一个名为标记-清除 (Mark-Sweep) 的 GC 算法。该算法分两个阶段进行:

  1. 标记阶段:GC 遍历内存并标记所有可到达的对象。可到达的对象是指仍然被应用程序使用的对象。
  2. 清除阶段:GC 遍历内存并清除所有未标记的对象,释放其占用的内存。

Go 的并发 GC

Go 的 GC 算法是并发的,这意味着它可以同时执行标记和清除阶段。这使得 Go 可以在应用程序继续执行时进行 GC,从而最大限度地减少 STW 时间。

Tri-Color 标记

Go 使用了一种称为 Tri-Color 标记的技术来实现并发 GC。该技术将对象标记为三种颜色:

  • 白色:未标记的对象。
  • 灰色:正在标记的对象。
  • 黑色:已标记的对象。

GC 并发地遍历内存,将白色对象标记为灰色,然后将灰色对象标记为黑色。当所有可到达的对象都被标记为黑色后,GC 就会开始清除白色对象。

增量清除

Go 还使用了一种称为增量清除的技术。该技术将内存划分为称为“区域”的较小块。GC 一次清除一个区域,这允许应用程序在其他区域继续执行。增量清除进一步减少了 STW 时间。

逃逸分析

Go 还使用了一种称为逃逸分析的优化技术。逃逸分析确定哪些对象存储在堆中,哪些存储在栈中。存储在栈中的对象在退出函数时自动释放,因此不需要 GC。逃逸分析减少了需要 GC 的对象数量,从而减少了 STW 时间。

总结

Go 在 GC 时 STW 时间短的原因有多种:

  • 并发的标记-清除算法
  • Tri-Color 标记技术
  • 增量清除技术
  • 逃逸分析

这些优化技术共同作用,使 Go 能够在不严重影响应用程序性能的情况下进行高效的垃圾回收。因此,Go 应用程序可以享受高吞吐量和低延迟,即使在 GC 期间也是如此。

ismydata 管理员 answered 7 月 ago

Go 是一种以其高效的垃圾回收 (GC) 机制而闻名的编程语言。与其他语言不同,Go 的 GC 采用一种称为并发标记和清除 (CMS) 的方法,这有助于最大限度地减少垃圾回收期间应用程序的停顿时间或 STW 时间。

并发标记和清除 (CMS)

传统 GC 方法在执行 GC 之前需要停止应用程序,这会导致严重的 STW 问题。而 CMS 允许 GC 线程在应用程序运行时并发进行标记和清除操作:

  • 标记阶段:GC 线程并行扫描应用程序的内存,标记出不再可访问的对象。
  • 清除阶段:GC 线程清除标记为要回收的对象,释放它们的内存。

由于标记和清除步骤是并发的,因此应用程序可以继续运行,而不会受到 GC 中断。

Go 中的 STW 时间

虽然 CMS 显著减少了 GC 期间的 STW 时间,但 Go 仍然需要一些短暂的 STW 时期:

  • *抢占世界 (Stop-the-World) *:在启动 GC 周期之前,需要短暂的 STW 以确保内存一致性。这段 STW 时间通常非常短暂,仅需几微秒。
  • 重置根指针 (Reset Roots):GC 完成后,需要进行短暂的 STW 以重置应用程序的根指针,指向 GC 后可用的对象。

优化 STW 时间

Go 团队已经采取了多种优化措施来进一步缩短 STW 时间:

  • 增量标记:标记阶段是分段进行的,这样应用程序就不用长时间暂停。
  • 增量清除:清除阶段也是分段进行的,这使得应用程序可以尽快释放已回收的内存。
  • 多个 GC 线程:Go 可以在多核系统上并行运行多个 GC 线程,以进一步加速标记和清除过程。

实际 STW 时间

Go 的实际 STW 时间因应用程序和机器配置而异。一般来说,小型应用程序的 STW 时间在几微秒到几毫秒之间,而大型应用程序的 STW 时间可能达到几十毫秒。

与其他语言的比较

与其他具有 GC 机制的语言相比,Go 的 STW 时间非常短。例如,Java 和 C# 的 GC 可能会导致数百毫秒甚至数秒的 STW 时间。这使得 Go 非常适合需要实时响应的应用程序。

结论

Go 的 CMS GC 机制、优化以及增量标记和清除方法相结合,使它在 GC 时具有非常短的 STW 时间。这使得 Go 非常适合对应用程序性能至关重要的场景,例如 web 服务器、微服务和分布式系统。

公众号