golang中也使用分代概念分配内容,同样也是用标记清除算法做垃圾回收。
-
tiny :size < 16 bytes && has no pointer(noscan);
-
small :has pointer(scan) || (size >= 16 bytes && size <= 32 KB);
-
large :size > 32 KB
golang最新的垃圾回收中标记算法优化了挂起线程的算法,作为云原生语言,就是挂起几毫秒也是无法容忍的,最新的标记算法中引入了所谓的“三色标记法”来优化STW问题。
三色标记法
第一步:新创建的对象都是白色
第二步:从root Object开始遍历,经过的对象:A、C、D、B变为灰色
第三步:遍历灰色对象应用的对象,从白色变为灰色,同时将之前灰色的对象变成黑色
第四步:重复第三步,直到没有灰色对象
第五步:回收白色对象
屏障机制
在golang的GC回收时,没有挂起所有线程,所以在操作三色标记时,程序仍旧在操作对象,接下来演练一个场景
可以看出引出这个问题的核心原因
- 黑色的对象指向了白色对象
- 灰色对象也失去白色对象的关联
强-弱三色不变式
- 强三色不变式:不存在黑色指向白色的关联
- 弱三色不变式:所有被黑色对象引用的白色对象都处于灰色
插入屏障
在A对象引用B对象时,B对象被标记为灰色。这个只操作堆内存中的数据,不操作栈内存中的数据,栈中的黑色指向白色时还是会STW,因为栈中的操作相对比较快
案例:堆内存中的C对象引用了栈内存中的E,此时E标记为灰色
删除屏障
被删除的对象,如果自身为灰色或者白色,那么被标记为灰色。
案例:A扫描开始时删除了B的引用,B标记为灰色
混合写屏障
在GO V1.8版本引入了混合写屏障机制
- 在GC开始时,将栈中的对象都标记为黑色
- GC期间创建栈对象永远标记为黑色
- 被删除的对象标记为灰色
- 被添加的对象标记为灰色
这里需要大量的案例来说明这四个操作,就不一一叙述了,基本上就是上述的案例的微变。可以把条件赋值到上面的图中自行模拟。
文章评论