1.什么是标记清除法?
首先要进行STW(stop the word - 程序暂停)
标记清除算法(Mark Sweep Algorithm),包括标记(Mark)和清除(Sweep)两个阶段:
- 标记阶段:从根对象开始,查找并标记堆中所有存活的对象
- 清除阶段:遍历堆中所有对象,回收未被标记的对象
2.标记清除法的缺点?
- STW,stop the world;让程序暂停,程序出现卡顿 (重要问题);
- 标记需要扫描整个heap;
- 清除数据会产生heap碎片。
3.什么是三色标记法?
三色标记法将程序中的对象分为三类:白色、灰色和黑色
- 白色:在回收开始阶段,所有对象都标记为白色;在回收结束后,所有白色对象均不可达,其内存将被释放
- 灰色:已被垃圾收集器访问到的对象,是一种中间状态。
- 黑色:已被垃圾收集器访问到的对象,且其引用都已被扫描到,黑色对象中任何一个指针都不可能直接指向白色对象
- 初始状态:所有对象都是白色的
- 扫描根对象:从根对象开始扫描,将所有可达对象标记为灰色,并放入待处理集合中
- 处理灰色对象:从待处理集合中取出灰色对象,将它们引用的对象标记为灰色,并将这些新标记的对象加入待处理集合中,同时将自身标记为黑色。
- 重复扫描:重复第3步,直到待处理集合为空。此时,所有白色对象都是不可达的垃圾对象,可以进行回收
3.没有STW下的三色标记法会遇到的问题?
条件1:一个白色对象被黑色对象引用(白色被挂在黑色下)
条件2:灰色对象与它之间的可达关系的白色对象遭到破坏(灰色同时丢了该白色)如果当以上两个条件同时满足时,就会出现对象丢失现象!
如果出现满足上面两个条件的场景就会把已经被指向的对象回收。如下图所示。
3.1 有哪些是根节点?
- 全局变量:程序在编译期就能确定的那些存在于程序整个生命周期的变量
- 执行栈上的对象或指针:每个 goroutine 都包含自己的执行栈,这些执行栈上2的对象包含栈上的变量及指向分配的堆内存区块的指针。
- 寄存器中的变量:寄存器的值可能表示一个指针,参与计算的这些指针可能指向某些赋值器分配的堆内存区块
强弱三色不变性
-
强三色不变形
强三色不变色实际上是强制性的不允许黑色对象引用白色对象,这样就不会出现有白色对象被误删的情况。
-
弱三色不变性
弱三色不变式强调,黑色对象可以引用白色对象。但是要满足下面两者之一。
- 这个白色对象必须存在其他灰色对象对它的引用
- 它的链路上游存在灰色对象。
为了遵循上述的两个方式,GC算法演进到两种屏障方式,“插入屏障”, “删除屏障”,“混合写屏障”。
什么是内存屏障
就是加入了一段代码进行赋值,比如写屏障将被引用对象标记为灰色。
什么是写屏障
在A对象引用B对象的时候,B对象被标记为灰色。(将B挂在A下游,B必须被标记为灰色)
满足: 强三色不变式
空间的特点是容量小,但是要求相应速度快,因为函数调用弹出频繁使用, 所以“插入屏障”机制,在栈空间的对象操作中不使用. 而仅仅使用在堆空间对象的操作中.
为什么不在栈中使用?
因为栈空间调用更加频繁,且更加快速,这里如果每次插入的时候都检查,会让栈的速度变慢,而栈空间和堆空间来比较的话,就是快,所以这里为了性能,不进行插入屏障,而是在最后再重新扫描一次
因为仅在堆空间中引入屏障,所以栈空间中可能出现有一个黑色对象引入白色对象的情况。为了解决这个问题,要对栈重新进行三色标记扫描, 但这次为了对象不丢失, 要对本次标记扫描启动STW暂停. 直到栈空间的三色标记结束.
什么是删除屏障
具体操作: 被删除的对象,如果自身为灰色或者白色,那么被标记为灰色。
满足: 弱三色不变式.
混合写屏障
1、GC开始将栈上的对象全部扫描并标记为黑色(之后不再进行第二次重复扫描,无需STW),
2、GC期间,任何在栈上创建的新对象,均为黑色。
3、被删除的对象标记为灰色。
4、被添加的对象标记为灰色。