Go垃圾回收
参考资料:
本篇只是为了自己方便复习,如有错误欢迎指正
演变过程
- V 1.3及之前:标记清除法
- V 1.5:三色标记法
- V 1.8:混合写屏障
术语解释
- GC:Garbage Collection,垃圾回收,一种自动内存管理机制
- 赋值器:程序代码,程序执行过程中,可能改变对象的引用关系,或创建新的引用
- 回收器:干掉程序中不再被引用的对象
- STW:Stop the world,停止所有的赋值器、中断程序逻辑,以确定引用关系
- 根对象:赋值器不需要通过其他对象就可以直接访问到的对象,比如全局变量和执行栈
V1.3 标记清除法
- 过程:
① STW
② 从根节点出发,标记所有可达节点
③ 停止STW,回收所有未标记对象 - 优点:算法简单
- 缺点:需要STW,很影响性能
V1.5 三色标记法
- 三色:
① 黑色:活跃的对象,已被垃圾收集器访问到,且所有字段都已被扫描
② 灰色:活跃的对象,已被垃圾收集器访问到,但存在指向白色对象的外部指针,垃圾收集器需要继续扫描其子对象
③ 白色:潜在的垃圾,未被垃圾收集器访问到的对象。在回收开始阶段,所有对象都被标记为白色;回收结束后,白色对象不可达,会被清除 - 过程:
① 初始时,将所有节点标记为白色
② 遍历根节点,将直接可达对象标记为灰色
③ 遍历灰色对象,将直接可达对象标记为灰色,自身变为黑色
④ 重复②和③直到没有灰色对象
⑤ 清除所有白色对象 - 是否仍需要STW?为什么?
仍然需要STW。举个例子,如果没有STW,在扫描过程中灰色对象解除了对白色对象的引用,但此时又有黑色对象引用了这个白色对象,由于黑色对象不会再被扫描,灰色对象会再被扫描,最终这个被引用的白色对象不会被扫描到,会被清除。 - 如何解决上文提到的问题?
出现对象丢失主要有两个原因:
① 白色对象被黑色对象引用
② 灰色对象与白色对象之间的可达关系遭到破坏
针对这两个问题的解决方案分别为:
① 强三色不变性:黑色对象只能指向黑色或灰色对象,不可直接指向白色对象
② 弱三色不变性:黑色对象可以指向白色对象,但白色对象的上游必须有灰色对象
据此解决方案实现的两种屏障机制:
① 插入写屏障:当一个对象引用另一个对象时,将另一个对象标记为灰色;但是栈上并不会实现插入写屏障,所以仍需要对栈上的空间进行STW
② 删除写屏障:如果被删除引用的对象自身为灰色或白色,那么被标记为灰色;但是回收精度低,因为当一个对象的引用被删除后,哪怕没有任何其他对象引用它,它依旧会存活到下一轮。 - 插入写屏障和删除写屏障是否还需要STW?
① 插入写屏障结束时,需要STW重新扫描栈,标记栈上引用的白色对象的存活
② 删除写屏障需要在GC开始时扫描堆栈来记录初始快照,这个过程会保护开始时刻的所有存活对象
V1.8 混合写屏障
- 规则:
① GC刚开始时,将栈上的全部可达对象标记为黑色
② GC期间,任何在栈上创建的对象均为黑色
③ 堆上被删除/添加的对象标记为灰色 - 不再需要STW
- 一个对象引用另一个对象的前提:另一个对象是可达的,如果有一个白色节点,没有任何可达路径,那么别人是无法引用到它的,也就不存在误删除的情况