Go的GC
2023年12月8日
机制:三色标记法 + 混合写屏障机制。 (栈无写屏障,堆有写屏障)
- 三色标记法。
- 初始对象全白
- 从根遍历。栈直接引用对象置黑,堆直接引用对象置灰。
- 遍历灰对象。引用置灰,当前灰置黑。 重复此步骤至无灰对象。
- 剩下的白对象回收。
- 混合写屏障机制。
- 栈:不用混合写屏障。新增对象直接置黑。 新增或删除引用(可以是堆上)不改变被引用对象颜色。
- 堆:启用混合写屏障。添加、删除的对象都标记为灰色。
流程:标记-清除
- 暂停用户程序STW,打开混合写屏障 和 并发垃圾收集器,恢复用户程序
- 并发标记。(三色标记法。扫描Goroutine期间会暂停当前处理器。)
- 暂停用户程序STW,关闭写屏障,恢复用户程序
- 并发清除。
触发GC
- 主动:手动调用
runtime.GC()
函数 - 被动:内存自上次GC增长一倍时自动触发。可以通过
debug.SetGCPercent(percent int)
调节百分比。 - 被动:默认如果2分钟内没有触发GC,则触发一次。
- 被动:新建小对象时如果需要申请新的mcache内存管理单元或者分配新建大于32KB大对象时可能触发。
防止频繁GC
- 压舱石。 声明一个大的切片,它被分配到堆内存上,但是并未使用,所以只占用虚拟内存。但是达到了最低GC内存的效果。 但是你要根据稳定运行占用的内存大小预估好一个适当的值。 (windows可能不适用)
- 软内存限制。版本>=1.19,为了防止前期内存占用低每增长一倍而频繁GC地情况,通过设置
debug.SetGCPercent(-1)
或GOGC=off
关闭内存增长GC,并且debug.SetMemoryLimit(limit int64)
设置为 70% 。 此方式在go独占服务器的时候可以使用。