GC垃圾回收
1.3版本以前: 清除 (mark and sweep) 算法(两色标记)
- 启动STW–>Mark标记–>Sweep清除–>停止STW
1.3、1.4:提前停止STW
- 启动STW–>Mark标记–>停止STW–>Sweep清除
- 以上回收算法的问题:
- STW,stop the world;让程序暂停,程序出现卡顿 (重要问题) ;
- 标记需要扫描整个 heap;
- 清除数据会产生 heap 碎片。
1.5版本以后:三色并发标记法
-
步骤
第一步 , 每次新创建的对象,默认的颜色都是标记为 “白色”
第二步 , 每次 GC 回收开始,会从根节点开始遍历所有对象(单层非递归),把遍历到的对象从白色集合放入 “灰色” 集合
第三步 , 遍历灰色集合,将灰色对象引用的对象从白色集合放入灰色集合,之后将此灰色对象放入黑色集合
第四步 , 重复 第三步 , 直到灰色中无任何对象
第五步 : 回收所有的白色标记表的对象,也就是回收垃圾 -
如果在三色并发标记法中不进行STW,则以下两种情况,在三色标记法中,是不希望被发生的。
条件 1 : 一个白色对象被黑色对象引用 (白色被挂在黑色下)
条件 2 : 灰色对象与它之间的可达关系的白色对象遭到破坏 (灰色同时丢了该白色)- 如果当以上两个条件同时满足时,就会出现对象丢失现象! -
我们让 GC 回收器,满足下面两种情况之一时,即可保对象不丢失。 这两种方式就是 “强三色不变式” 和 “弱三色不变式”。
“强 - 弱” 三色不变式
- 强三色不变式:不存在黑色对象引用到白色对象的指针。
- 弱三色不变式:所有被黑色对象引用的白色对象都处于灰色保护状态。为了遵循上述的两个方式,GC 算法演进到两种屏障方式,他们 是“插入屏障”, “删除屏障”
-
插入屏障 :在 A 对象 引用 B 对象 的时候, B 对象被标记为灰色 。(将 B 挂在 A 下游,B 必须被标记为灰色) 满足 : 强三色不变式 . (不存在黑色对象引用白色对象的情况了, 因为白色会强制变成灰色)
- 函数调用弹出频繁使用,所以 “插入屏障” 机制,在 栈空间的对象操作中不使用 . 而仅仅使用在堆空间对象的操作中 -
删除屏障 :具体操作: 被删除的对象,如果自身为灰色或者白色,那么被标记为灰色。 满足 : 弱三色不变式 . (保护灰色对象到白色对象的路径不会断)
- 这种方式的回收精度低,一个对象即使被删除了最后一个指向它的指针也依旧可以活过这一轮,在下一轮 GC 中被清理掉。
Go V1.8 版本引入了混合写屏障机制(hybrid write barrier),避免了对栈 re-scan 的过程,极大的减少了 STW 的时间。结合了两者的优点
- 1、GC 开始将 栈 上的对象全部扫描并标记为黑色 (之后不再进行第二次重复扫描,无需 STW),
- 2、GC 期间,任何在 栈 上创建的新对象,均为黑色。
- 3、被删除的对象标记为灰色。
- 4、被添加的对象标记为灰色。
- 满足: 变形的弱三色不变式.