Go是一种垃圾回收语言:
http://golang.org/doc/go_faq.html#garbage_collection
在这里,它说这是一个标志性的垃圾回收器,但是它没有深入研究细节,并且正在进行替代...但是,自Go发行以来,该段似乎没有太多更新。
它仍然是标记和扫描?是保守还是精确?它是世代相传的吗?
Go是一种垃圾回收语言:
http://golang.org/doc/go_faq.html#garbage_collection
在这里,它说这是一个标志性的垃圾回收器,但是它没有深入研究细节,并且正在进行替代...但是,自Go发行以来,该段似乎没有太多更新。
它仍然是标记和扫描?是保守还是精确?它是世代相传的吗?
Answers:
Go 1.4+垃圾收集器的计划:
在Go 1.1之上的Go 1.3垃圾收集器更新:
前往1.1垃圾收集器:
Go 1.0垃圾收集器:
用不同的GC替换GC是有争议的,例如:
gc说,下一个Go 1.5 并发的垃圾收集器将涉及“步调”。
这是本文提出的建议中可能适用于Go 1.5,但也有助于理解Go中的gc。
您可以看到1.5 之前的状态(停止世界:STW)
在Go 1.5之前,Go使用了并行的世界停止(STW)收集器。
尽管STW收集有很多缺点,但至少确实具有可预测和可控制的堆增长行为。
(照片来自GopherCon 2015演示文稿“ Go GC:解决Go 1.5中的延迟问题 ”)
STW收集器的唯一调整旋钮是“ GOGC”,即收集之间的相对堆增长。每次上一个收集的堆大小超过活动堆大小时,默认设置100%都会触发垃圾收集:
STW收集器中的GC计时。
Go 1.5引入了并发收集器。
与STW收集相比,这具有许多优点,但它可以堆增长难以控制,因为应用程序可以在垃圾收集器运行时分配内存。
(照片来自GopherCon 2015演示文稿“ Go GC:解决Go 1.5中的延迟问题 ”)
为了达到相同的堆增长限制,运行时必须更早地开始垃圾回收,但是更早地开始垃圾回收取决于许多变量,其中许多是无法预测的。
- 太早启动收集器,应用程序将执行过多的垃圾收集,浪费CPU资源。
- 启动收集器为时已晚,应用程序将超过所需的最大堆增长。
在不牺牲并发性的情况下实现正确的平衡需要仔细调整垃圾收集器的速度。
GC步调旨在沿两个维度进行优化:堆增长和垃圾收集器使用的CPU。
GC起搏的设计包含四个组件:
- 一个GC周期所需的扫描工作量的估算器,
- 一种机制,用于使更改程序在堆分配达到堆目标时执行估计的扫描工作量,
- 当mutator协助未充分利用CPU预算时,用于后台扫描的调度程序;以及
- GC触发器的比例控制器。
该设计平衡了两种不同的时间视图:CPU时间和堆时间。
- CPU时间与标准挂钟时间相似,但是传递
GOMAXPROCS
时间更快。
也就是说,如果GOMAXPROCS
为8,则每墙每秒经过8个CPU秒,而GC每墙每秒获得2秒的CPU时间。
CPU调度程序管理CPU时间。- 堆时间的流逝以字节为单位,并随着变量的分配而向前移动。
堆时间和挂墙时间之间的关系取决于分配率,并且可以不断变化。
Mutator协助管理堆时间的流逝,确保在堆达到目标大小时已完成估计的扫描工作。
最后,触发器控制器创建一个反馈循环,将这两个时间视图联系在一起,以优化堆时间和CPU时间目标。
这是GC的实现:
https://github.com/golang/go/blob/master/src/runtime/mgc.go
从源代码中的文档中:
GC与mutator线程同时运行,类型准确(也称为精确),允许多个GC线程并行运行。它是使用写入屏障的并发标记和清除。它是非世代和非紧凑的。使用每个P分配区域隔离的大小来完成分配,以最大程度地减少碎片,同时消除常见情况下的锁定。
建议使用“消除STW堆栈重新扫描”的建议,Go 1.8 GC可能会再次发展
从1.7版开始,堆栈重新扫描是无界且可能不重要的世界停止时间(STW)的唯一剩余来源。
我们建议通过切换到结合了Yuasa风格的删除写障碍[Yuasa '90]和Dijkstra风格的插入写障碍[Dijkstra '78]的混合写障碍来消除堆栈重新扫描的需要。。
初步实验表明,这可以将最坏情况下的 STW标志时间减少到50µs以下,并且这种方法可以使完全消除STW标志终止成为现实。