Golang 垃圾回收
垃圾回收 (Garbage Collection, 简称 GC)是编程语言中自动的内存管理机制,清除不再使用的对象,释放对应内存。
Golang GC 各版本变化
版本 | GC 算法 |
---|---|
v1.1 | STW(stop the world) |
v1.3 | Mark STW,Sweep(标记清除) |
v1.5 | 三色标记 |
v1.8 | Hybrid wire barrier (三色标记基础加入写屏障) |
标记清除算法(mark and sweep, v1.3)
- 找出不可达对象,mark
- 回收标记好的对象
mark and sweep 算法在执行的时候,需要程序暂停,即 stop the world
标记清除算法存在的问题
- stop the world 程序会暂停,即程序会出现卡顿
- 标记需要扫描整个堆(heap)
- 清除数据会产生 heap 碎片
三色并发标记法(v 1.5)
该算法是在 v1.5 版本开始使用,这里的三色,对应垃圾回收过程中对象的三种状态:
- 灰色:对象还在标记队列中等待
- 黑色:对象已被标记,该对象不会在本次 GC 中被清理
- 白色:对象未被标记,该对象将会在本次 GC 中被清理
三色标记法的过程(v1.5)
初始阶段,所有对象都是白色:
GC 开始扫描,从根节点开始遍历,A 和 F 是根节点,将其标记为灰色对象, 即根节点先置灰。
GC 继续扫描灰色对象,将根节点的子节点标记为灰色对象。A 的子节点 B C D 被标记为灰色对象,A 被标记为黑色对象。F 没有子节点,也被标记为黑色对象,即根节点置黑,子节点置灰
GC 会循环遍历灰色对象,直到灰色对象之中没有节点结束。B、C、D没有子节点,会变为黑色对象,即循环遍历所有节点,将所有父节点置黑。
未被标记的 E、G、H 为白色对象,GC 便会回收这些白色对象,即回收未被标记的白色对象。
这一轮垃圾回收结束后,GC 会进行进一步操作,将黑色对象重新变为白色对象,供下一次垃圾回收使用。
垃圾回收优化-写屏障
STW (stop the world) 的目的是防止 GC 扫描时内存变化而停掉 goroutine, 而写屏障就是让 goroutine 与 GC 同时运行的手段。
虽然写屏障不能完全消除 STW,但是可以大大减少 STW 的时间。写屏障类似一种开关,在 GC 的特定时间开启,开启后指针传递时会把指针标记,即本轮不回收,下次GC时再确定。
GC 过程中新分配的内存会被立即标记,用的并不是写屏障技术,也即 GC 过程中分配的内存不会在本轮 GC 中回收。
垃圾回收优化-Mutator-Assist
为防止内存分配过快、在 GC 执行过程中,如果 goroutine 需要分配内存,那么这个 goroutine 会参与一部分 GC 的工作,这个机制叫做 Mutator Assist。
垃圾回收触发机制
每次内存分配时都会检查当前内存分配量是否 已经到达阈值,如果达到就立即启动 GC。内存增长率由环境变量
GOGC
控制,默认是 100,即每当内存扩大一倍时启动 GC。
之后堆内存达到上一次垃圾手机的 2 倍才会触发 GC.默认情况下,最长 2 分钟触发一次 GC。
程序代码中也可以使用 runtime.GC() 来手动触发 GC。这主要用于 GC 性能测试和统计。