Golang 中的垃圾回收次要利用三色标记法,GC 过程和其余用户 goroutine 可并发运行,但须要肯定工夫的 STW(stop the world),所谓三色标记法实际上就是通过三个阶段的标记来确定要革除的对象都有哪些
具体步骤
第一步 , 每次新创建的对象,默认的色彩都是标记为“红色”。
第二步, 每次 GC 回收开始, 会从根节点开始遍历所有对象,把遍历到的对象从红色汇合放入“灰色”汇合。这里 要留神的是,本次遍历是一次遍历,非递归模式,是从程序抽次可到达的对象遍历一层。
第三步, 遍历灰色汇合,将灰色对象援用的对象从红色汇合放入灰色汇合,之后将此灰色对象放入彩色汇合。
第四步, 反复第三步, 直到灰色中无任何对象。
当全副的可达对象都遍历完后,灰色标记表将不再存在灰色对象,目前全副内存的数据只有两种色彩,彩色和红色。那么彩色对象就是咱们程序逻辑可达(须要的)对象,这些数据是目前撑持程序失常业务运行的,是非法的有用数据,不可删除,红色的对象是全副不可达对象,目前程序逻辑并不依赖他们,那么红色对象就是内存中目前的垃圾数据,须要被革除。
第五步: 回收所有的红色标记表的对象. 也就是回收垃圾。剩下的就是全副依赖的彩色对象。
问题
为了在 GC 过程中保证数据的平安,咱们在开始三色标记之前就会加上 STW,在扫描确定黑白对象之后再放开 STW。然而很显著这样的 GC 扫描的性能切实是太低了。
那么 Go 是如何解决标记 - 革除 (mark and sweep) 算法中的卡顿 (stw,stop the world) 问题的呢?
没有 STW 的三色标记法
如果没有 STW,那么也就不会再存在性能上的问题,那么接下来咱们假如如果三色标记法不退出 STW 会产生什么事件?
如果三色标记过程不启动 STW,那么在 GC 扫描过程中,任意的对象均可能产生读写操作,这样就会存在一种状况,就是同时满足以下两个条件:
- 条件 1: 一个红色对象被彩色对象援用(红色被挂在彩色下)
- 条件 2: 灰色对象与它之间的可达关系的红色对象受到毁坏(灰色同时丢了该红色)
如果当以上两个条件同时满足时,就会呈现对象失落景象,即一个非法援用的对象被 gc 给当作垃圾对象谬误回收掉。
为了避免这种景象的产生,最简略的形式就是 STW,间接禁止掉其余用户程序对对象援用关系的烦扰,然而 STW 的过程有显著的资源节约,对所有的用户程序都有很大影响。那么是否能够在保障对象不失落的状况下正当的尽可能的进步 GC 效率,缩小 STW 工夫呢?答案是能够的,咱们只有应用一种机制,尝试去毁坏下面的两个必要条件就能够了。
这就引出了咱们接下来要讲的屏障机制。