1. 三色标记法
Q: 常见的 GC 实现方式有哪些?
所有的 GC 算法其存在形式可以归结为追踪(Tracing)GC和**引用计数(Reference Counting)**这两种形式的混合运用。
目前比较常见的实现方式有:
- 标记清扫:从根对象出发,将确定存活的对象进行标记,并清扫可以回收的对象
- 标记整理:为了解决内存碎片问题而提出,在标记过程中,将对象尽可能整理到一块连续的内存上
- 增量式:将标记与清扫的过程分批执行,每次执行很小的部分,从而增量的推进垃圾回收,达到近似实时、几乎无停顿的目的
- 增量整理:在增量式的基础上,增加对对象的整理过程
- 分代式:将对象根据存活时间的长短进行分类,存活时间小于某个值的为年轻代,存活时间大于某个值的为老年代,永远不会参与回收的对象为永久代。并根据分代假设对对象进行回收
- 引用计数:根据对象自身的引用计数来回收,当引用计数归零时立即回收
Q: Go 语言的 GC 使用的是什么?
Go 的 GC 目前使用的是无分代(对象没有代际之分)、不整理(回收过程中不对对象进行移动与整理)、并发(与用户代码并发执行)的三色标记清扫算法。
Q: 三色标记法是什么?
三色标记法是Go垃圾回收器使用的核心算法。
三色定义:
- 白色:未被访问的对象,垃圾回收结束后白色对象会被清理
- 灰色:已被访问但其引用对象还未完全扫描的对象,是待处理队列
- 黑色:已被访问且其所有引用对象都已扫描完成的对象,确认存活
标记流程:
- GC开始时所有对象都是白色
- 从GC Root(全局变量、栈变量等)开始将直接可达对象标记为灰色
- 不断从灰色队列中取出对象,扫描其引用的对象:
- 如果引用对象是白色就标记为灰色
- 当前对象所有引用扫描完成后标记为黑色
- 重复这个过程直到灰色队列为空
- 最终只剩下黑色和白色对象,黑色对象为存活对象,白色对象为垃圾对象
这个过程可以视为以灰色对象为波面,将黑色对象和白色对象分离,使波面不断向前推进,直到所有可达的灰色对象都变为黑色对象为止。
Q: Go语言GC的根对象到底是什么?
根对象在垃圾回收的术语中又叫做根集合,它是垃圾回收器在标记过程时最先检查的对象,包括:
- 全局变量:程序在编译期就能确定的那些存在于程序整个生命周期的变量
- 执行栈:每个 goroutine 都包含自己的执行栈,这些执行栈上包含栈上的变量及指向分配的堆内存区块的指针
- 寄存器:寄存器的值可能表示一个指针,参与计算的这些指针可能指向某些赋值器分配的堆内存区块
Q: Go 语言中 GC 的流程是什么?
| 阶段 | 说明 | 赋值器状态 |
|---|---|---|
| SweepTermination | 清扫终止阶段,为下一个阶段的并发标记做准备工作,启动写屏障 | STW |
| Mark | 扫描标记阶段,与赋值器并发执行,写屏障开启 | 并发 |
| MarkTermination | 标记终止阶段,保证一个周期内标记任务完成,停止写屏障 | STW |
| GCoff | 内存清扫阶段,将需要回收的内存归还到堆中,写屏障关闭 | 并发 |
| GCoff | 内存归还阶段,将过多的内存归还给操作系统,写屏障关闭 | 并发 |
Q: STW 是什么意思?
STW 是 Stop the World 的缩写,通常意义上指的是用户代码被完全停止运行。STW 越长,对用户代码造成的影响(例如延迟)就越大。
早期 Go 对垃圾回收器的实现中 STW 长达几百毫秒,对时间敏感的实时通信等应用程序会造成巨大的影响。现代Go的GC已经将STW时间优化到微秒级别。