跳至内容
1. 三色标记法

1. 三色标记法

Q: 常见的 GC 实现方式有哪些?

所有的 GC 算法其存在形式可以归结为追踪(Tracing)GC和**引用计数(Reference Counting)**这两种形式的混合运用。

目前比较常见的实现方式有:

  • 标记清扫:从根对象出发,将确定存活的对象进行标记,并清扫可以回收的对象
  • 标记整理:为了解决内存碎片问题而提出,在标记过程中,将对象尽可能整理到一块连续的内存上
  • 增量式:将标记与清扫的过程分批执行,每次执行很小的部分,从而增量的推进垃圾回收,达到近似实时、几乎无停顿的目的
  • 增量整理:在增量式的基础上,增加对对象的整理过程
  • 分代式:将对象根据存活时间的长短进行分类,存活时间小于某个值的为年轻代,存活时间大于某个值的为老年代,永远不会参与回收的对象为永久代。并根据分代假设对对象进行回收
  • 引用计数:根据对象自身的引用计数来回收,当引用计数归零时立即回收

Q: Go 语言的 GC 使用的是什么?

Go 的 GC 目前使用的是无分代(对象没有代际之分)、不整理(回收过程中不对对象进行移动与整理)、并发(与用户代码并发执行)的三色标记清扫算法

Q: 三色标记法是什么?

三色标记法是Go垃圾回收器使用的核心算法。

三色定义

  • 白色:未被访问的对象,垃圾回收结束后白色对象会被清理
  • 灰色:已被访问但其引用对象还未完全扫描的对象,是待处理队列
  • 黑色:已被访问且其所有引用对象都已扫描完成的对象,确认存活

标记流程

  1. GC开始时所有对象都是白色
  2. 从GC Root(全局变量、栈变量等)开始将直接可达对象标记为灰色
  3. 不断从灰色队列中取出对象,扫描其引用的对象:
    • 如果引用对象是白色就标记为灰色
    • 当前对象所有引用扫描完成后标记为黑色
  4. 重复这个过程直到灰色队列为空
  5. 最终只剩下黑色和白色对象,黑色对象为存活对象,白色对象为垃圾对象
这个过程可以视为以灰色对象为波面,将黑色对象和白色对象分离,使波面不断向前推进,直到所有可达的灰色对象都变为黑色对象为止。

Q: Go语言GC的根对象到底是什么?

根对象在垃圾回收的术语中又叫做根集合,它是垃圾回收器在标记过程时最先检查的对象,包括:

  • 全局变量:程序在编译期就能确定的那些存在于程序整个生命周期的变量
  • 执行栈:每个 goroutine 都包含自己的执行栈,这些执行栈上包含栈上的变量及指向分配的堆内存区块的指针
  • 寄存器:寄存器的值可能表示一个指针,参与计算的这些指针可能指向某些赋值器分配的堆内存区块

Q: Go 语言中 GC 的流程是什么?

阶段说明赋值器状态
SweepTermination清扫终止阶段,为下一个阶段的并发标记做准备工作,启动写屏障STW
Mark扫描标记阶段,与赋值器并发执行,写屏障开启并发
MarkTermination标记终止阶段,保证一个周期内标记任务完成,停止写屏障STW
GCoff内存清扫阶段,将需要回收的内存归还到堆中,写屏障关闭并发
GCoff内存归还阶段,将过多的内存归还给操作系统,写屏障关闭并发

Q: STW 是什么意思?

STWStop the World 的缩写,通常意义上指的是用户代码被完全停止运行。STW 越长,对用户代码造成的影响(例如延迟)就越大。

早期 Go 对垃圾回收器的实现中 STW 长达几百毫秒,对时间敏感的实时通信等应用程序会造成巨大的影响。现代Go的GC已经将STW时间优化到微秒级别。