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

use*_*432 107 garbage-collection go

Go是一种垃圾收集语言:

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

在这里它说它是一个标记和清除垃圾收集器,但它没有深入研究细节,并且正在进行替换......但是,自Go发布以来,这段似乎没有更新.

它仍然是标记和扫描?它是保守还是精确?这是世代的吗?

小智 113

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

  • 混合停止世界/并发收集器
  • 停止世界的部分限制在10ms的截止日期
  • 专用于运行并发收集器的CPU核心
  • 三色标记和扫描算法
  • 非代
  • 非压实
  • 完全准确
  • 如果程序正在移动指针,则会产生很小的成本
  • 与Go 1.3 GC相比,延迟更低,但也更有可能降低吞吐量

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

  • 并发扫描(导致暂停时间较短)
  • 完全准确

去1.1垃圾收集器:

  • 标记和扫描(并行实现)
  • 非代
  • 非压实
  • 大多数精确(堆栈帧除外)
  • 停止这世界
  • 基于位图的表示
  • 程序没有分配内存时的零成本(即:在C中移动指针的速度和C一样快,但实际上这比C运行得慢一些,因为Go编译器不像C编译器那样先进,如GCC)
  • 支持对象的终结器
  • 不支持弱引用

去1.0垃圾收集器:

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

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

  • 除了非常大的堆,目前还不清楚世代GC是否会更快整体
  • 包装"不安全"使得很难实现完全精确的GC和压缩GC

  • @uriel:是的,我在答案的第一项中提到了这一点 - 文本"(并行实现)". (3认同)
  • 那么用1.5.x更新这个答案只是为了制作一个好的历史记录. (3认同)

Von*_*onC 32

(对于Go 1.8 - 2017年第一季度,见下文)

下一个Go 1.5 并发垃圾收集器涉及能够"调整"所述gc.
以下是本文中提出的可能适用于Go 1.5 的提议,但也有助于理解Go中的gc.

你可以看到1.5 之前的状态(停止世界: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. 一种机制,让mutator在堆分配达到堆目标时执行估计的扫描工作量,
  3. 当mutator协助未充分利用CPU预算时,用于后台扫描的调度程序,以及
  4. GC触发器的比例控制器.

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

  • CPU时间就像标准挂钟时间,但通过GOMAXPROCS时间更快.
    也就是说,如果GOMAXPROCS是8,那么每秒墙就会有8个CPU秒通过,而每秒墙就会有两秒钟的CPU时间.
    CPU调度程序管理CPU时间.
  • 的通过堆时间以字节为单位和向前移动为存取器分配.

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


ber*_*rio 18

这是GC的实现:

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

来自源文档:

GC与mutator线程同时运行,类型准确(也称为精确),允许多个GC线程并行运行.它是一个使用写屏障的并发标记和扫描.它是非代数和非紧凑的.使用按P分配区域隔离的大小来完成分配,以最小化碎片,同时消除常见情况下的锁定.


Von*_*onC 8

Go 1.8 GC可能会再次发展,提议"消除STW堆栈重新扫描"

从Go 1.7开始,无限制且可能非平凡的世界末日(STW)时间的剩余来源是堆栈重新扫描.

我们建议通过切换到混合写屏障来消除对堆栈重新扫描的需要,该屏障结合了Yuasa风格的删除写屏障[Yuasa '90]Dijkstra风格的插入写屏障[Dijkstra '78].

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

公告是在这里,你可以看到相关的源提交是d70b0fe和更早版本.