gc不回收什么
- GC 不负责回收栈中的内存
- 栈是一块专用内存,专门为了函数执行而准备的,存储着函数中的局部变量以及调用栈
- 栈中的数据可以通过简单的编译器指令自动清理,也就不需要通过 GC 来回收了
垃圾回收算法
- 主流的两类垃圾回收算法有两种,分别是追踪式垃圾回收算法[1]和引用计数法( Reference counting )。而三色标记法是属于追踪式垃圾回收算法的一种
- 追踪式算法的核心思想是判断一个对象是否可达,因为一旦这个对象不可达就可以立刻被 GC 回收了
- 第一步找出所有的全局变量和当前函数栈里的变量,标记为可达。第二步,从已经标记的数据开始,进一步标记它们可访问的变量,以此类推,专业术语叫传递闭包。
三色标记法
- 对象用三种颜色表示,黑白灰。
- 初始化都是白色的,然后把全局变量和栈上的变量变成灰的
- 第二步把灰色的对象变成黑色,把原先灰色对象指向的变量变成灰色,以此类推,当发现没有对象可以被制成灰色时,白色的对象就可以清理了
垃圾回收流程
- 阶段一,marking setup 标记准备,在三色标记前,需要开启 write barrier 写屏障。运行过程中程序的函数栈中会有新分配的对象,就需要写屏障。写屏障主要是修改原先的写逻辑,在对象生成的时候给他着为灰色,因此打开写屏障会保证三色标记法在并发下安全运行
- 打开写屏障需要停止所有的goroutine,也就是stop the world (STW)
- 阶段二,marking标记。打开write barrier以后,开始用三色标记法标记。
- 在标记开始的时候,收集器会默认抢占 25% 的 CPU 性能,剩下的75%会分配给程序执行。但是一旦收集器认为来不及进行标记任务了,就会改变这个 25% 的性能分配。这个时候收集器会抢占程序额外的 CPU,这部分被抢占 goroutine 有个名字叫 Mark Assist 标记辅助。而且因为抢占 CPU的目的主要是 GC 来不及标记新增的内存,那么抢占正在分配内存的 goroutine 效果会更加好,所以分配内存速度越快的 goroutine 就会被抢占越多的资源。
- 阶段三,Mark termination 标记结束
- marking标记阶段结束后进入标记结束阶段,会关掉写屏障,开始stw,还需要计算下次清理的目标和计划,比如使用了mark assist 标记辅助,会促使下次gc提前
- 第四个阶段 sweeping concurrent 清理阶段,并发执行,无感知也没有延迟