Go 使用什么样的垃圾收集?

发布于 2024-12-10 19:03:07 字数 266 浏览 0 评论 0原文

Go 是一种垃圾收集语言:

http://golang.org/doc/go_faq.html#garbage_collection

在这里说它是一个标记和清除垃圾收集器,但它没有深入研究细节,并且替代品正在开发中......然而,自从 Go 发布以来,这一段似乎没有更新太多。

仍然是标记和清除吗?是保守的还是精确的?是一代人的吗?

Go is a garbage collected language:

http://golang.org/doc/go_faq.html#garbage_collection

Here it says that it's a mark-and-sweep garbage collector, but it doesn't delve into details, and a replacement is in the works... yet, this paragraph seems not to have been updated much since Go was released.

It's still mark-and-sweep? Is it conservative or precise? Is it generational?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

生生漫 2024-12-17 19:03:07

Go 1.4+ 垃圾收集器的计划:

  • 混合 stop-the-world/并发收集器
  • stop-the-world 部分受 10ms 截止时间限制
  • CPU 核心专用于运行并发收集器
  • 三色标记和清除算法
  • 非分代非
  • - 压缩
  • ,那么完全精确的
  • 如果程序正在以较低的延迟移动指针
  • 会产生很小的成本,但很可能也会降低吞吐量,而不是 Go 1.3 GC

Go 1.3 垃圾收集器在 Go 1.1 之上进行更新:

  • 并发扫描(导致更短的暂停时间)
  • 完全精确

Go 1.1 垃圾收集器:

  • 标记和扫描(并行实现)
  • 非分代
  • 非压缩
  • 大部分精确(堆栈帧除外)
  • 停止世界
  • 基于位图的
  • 表示零成本程序不分配内存(即:混洗指针与 C 中一样快,尽管实际上运行速度比 C 慢一些,因为 Go 编译器不像 GCC 等 C 编译器那么先进)
  • 支持终结器对象
  • 不支持弱引用

Go 1.0 垃圾收集器:

  • 与 Go 1.1 相同,但垃圾收集器不是最精确的,而是保守的。保守的GC能够忽略诸如[]byte之类的对象。

用不同的GC替换GC是有争议的,例如:

  • 除了非常大的堆之外,不清楚分代GC是否会更快整体
  • 包“不安全”使得很难实现完全精确的GC和压缩GC

Plans for Go 1.4+ garbage collector:

  • hybrid stop-the-world/concurrent collector
  • stop-the-world part limited by a 10ms deadline
  • CPU cores dedicated to running the concurrent collector
  • tri-color mark-and-sweep algorithm
  • non-generational
  • non-compacting
  • fully precise
  • incurs a small cost if the program is moving pointers around
  • lower latency, but most likely also lower throughput, than Go 1.3 GC

Go 1.3 garbage collector updates on top of Go 1.1:

  • concurrent sweep (results in smaller pause times)
  • fully precise

Go 1.1 garbage collector:

  • mark-and-sweep (parallel implementation)
  • non-generational
  • non-compacting
  • mostly precise (except stack frames)
  • stop-the-world
  • bitmap-based representation
  • zero-cost when the program is not allocating memory (that is: shuffling pointers around is as fast as in C, although in practice this runs somewhat slower than C because the Go compiler is not as advanced as C compilers such as GCC)
  • supports finalizers on objects
  • there is no support for weak references

Go 1.0 garbage collector:

  • same as Go 1.1, but instead of being mostly precise the garbage collector is conservative. The conservative GC is able to ignore objects such as []byte.

Replacing the GC with a different one is controversial, for example:

  • except for very large heaps, it is unclear whether a generational GC would be faster overall
  • package "unsafe" makes it hard to implement fully precise GC and compacting GC
女皇必胜 2024-12-17 19:03:07

(对于 Go 1.8 - 2017 年第一季度,请参阅下文

下一个 Go 1.5 并发垃圾收集器涉及gc 说,能够“步调”。
这是本文中提出的一项提案,可能会适用于 Go 1.5,但也有助于理解中的 gc去。

您可以看到 1.5 之前的状态(Stop The World:STW)

在 Go 1.5 之前,Go 使用了并行 stop-the-world (STW) 收集器。
虽然 STW 收集有很多缺点,但它至少具有可预测且可控的堆增长行为。

https://40.media.tumblr.com/49e6556b94d75de1050c62539680fcf9/tumblr_inline_nr6qq8D9FE1sdck2n_540.jpg

(照片来自 GopherCon 2015 演示文稿“Go GC:解决 Go 中的延迟问题1.5")

STW 收集器的唯一调节旋钮是“GOGC”,即收集之间的相对堆增长。默认设置 100% 每当堆大小比上次收集时的实时堆大小增加一倍时就会触发垃圾收集:

https://docs.google.com/drawings/image?id=sLJ_JvGfPfPnojLlEGLCWkw&rev=1&h=113&w=424&ac=1

STW 收集器中的 GC 计时。

Go 1.5 引入了并发收集器
与 STW 收集相比,这具有许多优点,但它使堆增长更难以控制,因为应用程序可以在垃圾收集器运行时分配内存。

https://40.media.tumblr.com/783c6e557b427a5c023520578740eb94/tumblr_inline_nr6qqpmaJx1sdck2n_540.jpg

(照片来自 GopherCon 2015 演示文稿“Go GC:解决 Go 中的延迟问题1.5")

为了达到相同的堆增长限制,运行时必须提前开始垃圾收集,但提前多少取决于许多变量,其中许多变量无法预测。

  • 过早启动收集器,应用程序将执行过多的垃圾收集,浪费 CPU 资源。
  • 太晚启动收集器,应用程序将超过所需的最大堆增长。

要在不牺牲并发性的情况下实现正确的平衡,需要仔细调整垃圾收集器的节奏。

GC 节奏旨在沿着两个维度进行优化:堆增长和垃圾收集器使用的 CPU。

https://docs.google.com/drawings/image?id=sEZYCf7Mc0E0EGmy4gho3_w&rev=1&h=235&w= 457&ac=1

GC 节奏的设计由四个部分组成:

  1. GC 周期所需的扫描工作量的估算器,
  2. 一种机制,供变异器在堆分配达到堆目标时执行估计的扫描工作量,
  3. 当 mutator 未充分利用 CPU 预算时用于后台扫描的调度程序,以及
  4. GC 触发器的比例控制器。

该设计平衡了两种不同的时间视图:CPU 时间和堆时间

  • CPU 时间类似于标准挂钟时间,但速度比 GOMAXPROCS 倍快。
    也就是说,如果 GOMAXPROCS 为 8,则每墙秒经过 8 个 CPU 秒,GC 每墙秒获得两秒的 CPU 时间。
    CPU 调度程序管理 CPU 时间。
  • 堆时间的流逝以字节为单位,并随着变元分配而向前移动。

堆时间和挂机时间之间的关系取决于分配率,并且可以不断变化。
Mutator 协助管理堆时间的流逝,确保在堆达到目标大小时已完成估计的扫描工作。
最后,触发器控制器创建一个反馈循环,将这两个时间视图联系在一起,从而优化堆时间和 CPU 时间目标。

(For Go 1.8 - Q1 2017, see below)

The next Go 1.5 concurrent Garbage Collector involve being able to "pace" said gc.
Here is a proposal presented in this paper which might make it for Go 1.5, but also helps understand the gc in Go.

You can see the state before 1.5 (Stop The World: STW)

Prior to Go 1.5, Go has used a parallel stop-the-world (STW) collector.
While STW collection has many downsides, it does at least have predictable and controllable heap growth behavior.

https://40.media.tumblr.com/49e6556b94d75de1050c62539680fcf9/tumblr_inline_nr6qq8D9FE1sdck2n_540.jpg

(Photo from GopherCon 2015 presentation "Go GC: Solving the Latency Problem in Go 1.5")

The sole tuning knob for the STW collector was “GOGC”, the relative heap growth between collections. The default setting, 100%, triggered garbage collection every time the heap size doubled over the live heap size as of the previous collection:

https://docs.google.com/drawings/image?id=sLJ_JvGfPfPnojLlEGLCWkw&rev=1&h=113&w=424&ac=1

GC timing in the STW collector.

Go 1.5 introduces a concurrent collector.
This has many advantages over STW collection, but it makes heap growth harder to control because the application can allocate memory while the garbage collector is running.

https://40.media.tumblr.com/783c6e557b427a5c023520578740eb94/tumblr_inline_nr6qqpmaJx1sdck2n_540.jpg

(Photo from GopherCon 2015 presentation "Go GC: Solving the Latency Problem in Go 1.5")

To achieve the same heap growth limit the runtime must start garbage collection earlier, but how much earlier depends on many variables, many of which cannot be predicted.

  • Start the collector too early, and the application will perform too many garbage collections, wasting CPU resources.
  • Start the collector too late, and the application will exceed the desired maximum heap growth.

Achieving the right balance without sacrificing concurrency requires carefully pacing the garbage collector.

GC pacing aims to optimize along two dimensions: heap growth, and CPU utilized by the garbage collector.

https://docs.google.com/drawings/image?id=sEZYCf7Mc0E0EGmy4gho3_w&rev=1&h=235&w=457&ac=1

The design of GC pacing consists of four components:

  1. an estimator for the amount of scanning work a GC cycle will require,
  2. a mechanism for mutators to perform the estimated amount of scanning work by the time heap allocation reaches the heap goal,
  3. a scheduler for background scanning when mutator assists underutilize the CPU budget, and
  4. a proportional controller for the GC trigger.

The design balances two different views of time: CPU time and heap time.

  • CPU time is like standard wall clock time, but passes GOMAXPROCS times faster.
    That is, if GOMAXPROCS is 8, then eight CPU seconds pass every wall second and GC gets two seconds of CPU time every wall second.
    The CPU scheduler manages CPU time.
  • The passage of heap time is measured in bytes and moves forward as mutators allocate.

The relationship between heap time and wall time depends on the allocation rate and can change constantly.
Mutator assists manage the passage of heap time, ensuring the estimated scan work has been completed by the time the heap reaches the goal size.
Finally, the trigger controller creates a feedback loop that ties these two views of time together, optimizing for both heap time and CPU time goals.

眼泪都笑了 2024-12-17 19:03:07

这是 GC 的实现:

https://github.com /golang/go/blob/master/src/runtime/mgc.go

来自源中的文档:

GC 与 mutator 线程同时运行,类型准确(又称精确),允许多个 GC 线程并行运行。它是使用写屏障的并发标记和清除。它是非分代和非压缩的。分配是使用每个 P 分配区域的大小隔离来完成的,以最大限度地减少碎片,同时消除常见情况下的锁。

This is the implementation of the GC:

https://github.com/golang/go/blob/master/src/runtime/mgc.go

From the docs in the source:

The GC runs concurrently with mutator threads, is type accurate (aka precise), allows multiple GC thread to run in parallel. It is a concurrent mark and sweep that uses a write barrier. It is non-generational and non-compacting. Allocation is done using size segregated per P allocation areas to minimize fragmentation while eliminating locks in the common case.

生来就爱笑 2024-12-17 19:03:07

Go 1.8 GC 可能会再次发展,提案“消​​除 STW”堆栈重新扫描”

从 Go 1.7 开始,剩余的一个无限且可能不平凡的世界停止 (STW) 时间来源是堆栈重新扫描。

我们建议通过切换到结合了 Yuasa 式删除写入屏障 [Yuasa '90]Dijkstra 式插入写屏障 [Dijkstra '78]。< /p>

初步实验表明,这可以将最坏情况下的 STW 时间减少到 50μs 以下,并且这种方法可以使完全消除 STW 标记终止变得可行。

公告在此,您可以查看相关来源提交是d70b0fe 及更早版本。

Go 1.8 GC might evolve again, with the proposal "Eliminate STW stack re-scanning"

As of Go 1.7, the one remaining source of unbounded and potentially non-trivial stop-the-world (STW) time is stack re-scanning.

We propose to eliminate the need for stack re-scanning by switching to a hybrid write barrier that combines a Yuasa-style deletion write barrier [Yuasa '90] and a Dijkstra-style insertion write barrier [Dijkstra '78].

Preliminary experiments show that this can reduce worst-case STW time to under 50µs, and this approach may make it practical to eliminate STW mark termination altogether.

The announcement is here and you can see the relevant source commit is d70b0fe and earlier.

水晶透心 2024-12-17 19:03:07

我不确定,但我认为当前(提示)GC 已经是并行的,或者至少是一个 WIP。因此,停止世界属性不再适用或在不久的将来也不会适用。也许其他人可以更详细地澄清这一点。

I'm not sure, but I think the current (tip) GC is already a parallel one or at least it's a WIP. Thus the stop-the-world property doesn't apply any more or will not in the near future. Perhaps someone other can clarify this in more detail.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文