
Go1.3标记清除法
步骤
- 进行STW(stop the world即暂停程序业务逻辑),然后从main函数开始找到不可达的内存占用和可达的内存占用
- 开始标记,程序找出可达内存占用并做标记
- 标记结束,清除未标记的内存占用
- 结束STW,让程序继续运行,循环该过程直到main生命周期结束
优化
由于STW会影响程序的性能,因此将步骤3和步骤4的顺序调换,让步骤3的垃圾清除步骤与程序同时进行,能够减小STW的时长。

Go1.5三色标记法
三色定义
三色标记算法将程序中的对象分成白色、灰色,黑色三类:
- 白色对象表示暂无对象引用的潜在垃圾,其内存可能会被垃圾收集器回收
- 灰色对象表示白色到黑色的中间状态,垃圾回收器会继续扫描它引用的对象
- 黑色对象表示活跃的对象,它引用的对象都被扫描
步骤
- 将所有对象标记为白色节点
- 从根节点开始,将第一次遍历到的节点标记为灰色
- 遍历灰色节点,将遍历到的白色节点标记为灰色,并把该灰色节点标记为黑色
- 循环这个过程
- 直到不存在灰色节点,回收所有的白色节点
图解
将对象标记为白色节点
从根节点遍历得到灰色节点
遍历灰色节点,将灰色标记为黑色,遍历到的节点标记为灰色
重复操作
直到没有灰色节点

Bug
当程序和GC同时执行时,如果一个节点还没有被遍历,此时该节点为白色,程序运行时将原本的引用删除,让一个黑色节点引用该节点,则该节点不会被遍历,最后被删除。
对象2和对象4被标记为灰色
对象5被遍历之前被改变了引用
被对象1引用的对象5不会变成黑色,最后被删除

解决办法
三色不变性
让程序运行过程满足强三色不变性或者弱三色不变性。
- 强三色不变性:黑色对象不会指向白色对象,只会指向灰色对象或者黑色对象。
- 弱三色不变性:黑色对象指向的白色对象必须包含一条从灰色对象经由多个白色对象的可达路径。
屏障机制
在程序的执行过程中添加一个屏障机制实现两种不变性 屏障机制分为插入屏障和删除屏障,插入屏障实现的是强三色不变式,删除屏障则实现了弱三色不变式。为了保证栈的运行效率,屏障只对堆上的内存对象启用,栈上的内存会在GC结束后启用STW重新扫描。
插入屏障
使程序满足强三色不变性,当白色节点被黑色节点引用时,将白色节点变为灰色,从而保留这个节点。缺陷:如果白色节点被栈上的黑色节点引用,不会触发插入屏障,最后还是会被删除。
删除屏障
使程序满足弱三色不变性,当白色节点的引用被删除时,将白色节点变为灰色,从而保留这个节点。缺陷:如果没有黑色节点引用这个白色节点,那么本来作为垃圾的白色节点将会被保留到下一轮GC。
go1.8混合写屏障
概念
解决插入写屏障和删除写屏障在结束时需要STW来重新扫描栈带来的性能问题
步骤
- GC开始将栈上的对象全部扫描并标记为黑色
- GC期间任何在栈新创建的对象都标记为黑色
- 堆上被删除的对象标记为灰色
- 堆上被添加的对象标记为灰色
操作场景
某时刻栈和堆的情况(栈一开始就都是黑的)
栈上新增对象4,堆上新增对象d
栈上删除对象1,堆上删除对象3
栈上删除栈上新增,堆上删除堆上新增
堆上删除栈上新增
栈上删除堆上新增
