go语言的垃圾回收(GC)概述

2020-07-09 00:00:00 算法 对象 引用 回收 标记

垃圾回收是语言的一个进步,其算法目前有几种经典的算法,说go的GC之前先说一下所有的GC的算法:

  1. 引用计算法:每一个对象都有一个计数器,当这个对象被引用一次时,计数器加一,减少一次引用时,计数器减一,这样当对象的计数器为0时,我们就可以进行回收了。PHP、Object等在使用。优点:回收快,算法简单,不需要STW(Stop The World,挂起程序)缺点:相互引用时无法回收,计数器增加消耗。
  2. Mark And Sweep 标记和清除算法:停止运行程序,从根变量开始遍历所有引用的对象,引用的对象标记为"被引用",没有被标记的进行回收。算法思想在 70 年代就提出了,是一种非常古老的算法。内存单元并不会在变成垃圾立刻回收,而是保持不可达状态,直到到达某个阈值或者固定时间长度。这个时候系统会挂起用户程序,也就是 STW,转而执行垃圾回收程序。垃圾回收程序对所有的存活单元进行一次全局遍历确定哪些单元可以回收。算法分两个部分:标记(mark)和清扫(sweep)。优点:解决了引用计数的缺点,既解决了相互引用的问题。缺点:由于标记需要停止程序(Stop The World),增加耗时,如果对象特别多时,可能需要停止程序几百毫秒。
  3. 三色标记法:属于标记个清除算法的一个改进版本。起初所有对象为白色;再从根出发遍历所有对象,标记为灰色,并放入一个队列;然后将灰色对象从队列取出来,再将其引用对象标记为黑色,自身标记为黑色,重复此步骤,待灰色对象队列为空时,所有白色对象既为垃圾。



还有一种是分代收集:一般情况有三代,java举例:新生代,老年代,代。当新生代中带阀值时将对象放入老年代,老年代也是如此放入代。不同代有不同的回收算法和回收频率。

go语言使用的是三色标记法。首先说一下go的GC触发条件:个就是阀值,当内存扩大一倍时,启用GC,再有一个就是默认两分钟执行一次。此外我们可以手动调用GC:runtime.FC()。

之前我们说过STW(Stop The World)是其性能的主要因素,在go的1.8版本开始,STW时间已经优化到100微秒,通常只需要10微秒以下即可。并且1.10版本后,对CPU的占用也进行了优化。大家可以看一下go的源码,在runtime包中,mgc.go文件,对其GC进行了详细的解释。


对于我们在写代码时,如果考虑GC性能问题,我有两个建议给大家,个是少用string字符串的 “+”号,第二个是小对象要尽量服复用,局部变量需要尽量少声名,多个的小对象可以放到结构体中,这样方便GC的扫描。这样做是尽可能的追求其性能,我们在写程序时,不仅要考虑功能,性能也是很重要的。

后续会有更多的模式和算法以及区块链相关的,如果你是想学习go语言或者是对设计模式或者算法感兴趣亦或是区块链开发工作者,都可以关注一下。(微信公众号/今日头条:Go语言之美,更多go语言知识信息等)。公众号会持续为大家分享更多干货。

如果大家觉得文章有帮助,欢迎转发!

相关文章