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

时间:2011-10-19 15:24:25

标签: garbage-collection go

Go是一种垃圾收集语言:

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

这里说它是一个标记和扫描垃圾收集器,但它没有深入研究细节,并且正在进行更换......但是,这段似乎没有更新,因为Go是释放。

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

5 个答案:

答案 0 :(得分:108)

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

  • hybrid stop-the-world / concurrent collector
  • 世界各地限制在10毫秒的截止日期
  • 专用于运行并发收集器的CPU核心
  • 三色标记和扫描算法
  • 非代
  • 非密实
  • 完全准确
  • 如果程序移动指针
  • 会产生一小笔费用
  • 比Go 1.3 GC
  • 更低的延迟,但最有可能也降低吞吐量

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

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

去1.1垃圾收集器:

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

去1.0垃圾收集器:

  • 与Go 1.1相同,但垃圾收集器并不是大多数都是保守的。保守的GC能够忽略诸如[] byte。
  • 之类的对象

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

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

答案 1 :(得分:30)

(对于Go 1.8 - Q1 2017, see below

下一个Go 1.5 并发垃圾收集器涉及能够"节奏" gc。
这是一个提交in this paper的提案,它可能适用于Go 1.5,但也有助于理解Go中的gc。

您可以在 1.5(停止世界:STW)之前看到状态

  

在Go 1.5之前,Go使用了并行停止世界(STW)收集器。
  虽然STW集合有许多缺点,但它至少具有可预测和可控的堆增长行为。

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

(照片来自GopherCon 2015演示" Go GC: Solving the Latency Problem in 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: Solving the Latency Problem in 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在堆分配达到堆目标时执行估计的扫描工作量,
  4.   
  5. 当mutator协助未充分利用CPU预算时进行后台扫描的调度程序,
  6.   
  7. GC触发器的比例控制器。
  8.         

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

         
        
    • CPU时间与标准挂钟时间相似,但速度提高GOMAXPROCS倍。
        也就是说,如果GOMAXPROCS为8,那么每隔一秒钟就会有8个CPU秒通过,而每秒一秒,GC会获得2秒的CPU时间。
        CPU调度程序管理CPU时间。
    •   
    • 堆时间的通过以字节为单位,并在mutators分配时向前移动。
    •   
         

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

答案 2 :(得分:17)

这是GC的实施:

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

来自资料来源:

  

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

答案 3 :(得分:8)

Go 1.8 GC可能会再次发展,proposal "Eliminate STW stack re-scanning"

  

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

     

我们建议通过切换到结合Yuasa-style deletion write barrier [Yuasa '90]Dijkstra-style insertion write barrier [Dijkstra '78]的混合写屏障来消除堆栈重新扫描的需要。

     

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

announcement is here您可以看到相关的来源提交是d70b0fe及更早。

答案 4 :(得分:2)

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