讲讲Go垃圾回收机制 | 豆包MarsCode AI刷题

78 阅读3分钟

Go1.3之前采用标记清除法,Go1.3之后采用三色标记法。Go1.8之后采用采用三色标记法+混合写屏障。 Go垃圾回收器是并发的,而且在程序运行过程中可以让GC和应用程序一起工作,从而最大限度地减少对应用的影响。

三色标记法:

将对象分为三种颜色:

  • 白色:尚未检查的对象,假设最初所有对象都是白色。
  • 灰色:已经发现但是其引用地对象尚未检查地对象。
  • 黑色:当前已检查并且其引用的对象也确认存活地对象。

过程:

  1. 初始化,将所有对象设为白色,将根集合(全局对象、栈上的对象等)标记为灰色。
  2. 标记:从灰色对象开始遍历,将所有被引用的白色对象变成灰色,遍历结束后把当前对象变黑。
  3. 扫描:不断重复以上过程,直到没有灰色对象。最终白色的对象即为未被引用地对象,可以回收。

三色不等式:

  • 强三色不等式:不存在黑色对象引用到白色对象的指针。
  • 弱三色不等式:所有被黑色对象引用的白色对象都处于灰色保护状态。

如果对象的引用被用户修改了,那么之前的标记就无效了,因此采用了写屏障技术,当对象新增或者更新会将其着色为灰色,确保这些改动不会导致存活的对象被错误地回收。

由于插入写屏障和删除写屏障在结束时需要STW来重新扫描,带来性能瓶颈,因此引入混合写屏障,分为四部:

  1. GC开始将栈上地对象全部扫描并标记为黑色(之后不再进行第二次重复扫描,无需STW)
  2. GC期间,任何在栈上创建的新对象,均为黑色。
  3. 被删除引用的对象标记为灰色
  4. 被添加引用的对象标记为灰色。

有界延迟

Go垃圾回收器设计目标之一是保证低延迟,以避免垃圾回收对应用程序性能造成显著地影响。因此Go语言设计了多种策略来限制每次垃圾回收所花费的时间,开发人员可以通过控制GOGC,或者debug.SetGCPercent()等方法来人工干预GC过程。

Go语言的GC流程

  1. 标记阶段:标记所有存活的对象。
  2. 清楚阶段:清楚那些未被标记的对象。
  3. 压缩阶段:调整堆中的对象以减少内存碎片。 主要是通过合理设置GC的策略与参数,来降低垃圾回收对程序性能的影响,使得内存管理变得更加简单。

调优是一个反复迭代的过程,持续监控和分析是关键。

GC调优,主要是两方面:一方面减少用户代码分配内存的数量(即对程序的代码行为进行调优),另一方面最小化Go的GC对CPU的使用率(即调整 GOGC)。

GO 进行GC调优有以下几个主要方式:

  • 配置 GOGC,控制触发 GC 的内存增长百分比,降低GC的频率。
  • 优化内存分配和释放,减少go对象分配和释放的频率。控制内存分配的速度,比如限制Goroutine的数量)
  • 调整数据结构和算法,减少并复用内存,比如减少指针的使用,再比如少量使用+连接string,避免重复扩容,再比如使用slice时提前分配足够的内存来降低扩容带来的拷贝。
  • 更新GO版本,利用最新的性能改进和垃圾回收优化。