主动:调用 runtime.GC
被动:
-
由系统监控,两分钟没有 GC 就强制 GC
-
步骤
-
暂停程序,对可达和不可达对象进行分类
-
开始标记
-
清除未标记的
-
停止暂停
缺点:需要 STW,标记时需要扫描整个 heap,清除时会产生 heap
在 v1.3 做了优化,清除的时候不需要 STW
V1.5-三色标记法
步骤
-
创建的对象为白色
-
从根节点执行,把遍历到的放到灰色集合中
-
遍历灰色对象,将灰色引用的白色放进灰色集合,然后将该灰色放进黑色集合
-
重复上一步,直到灰色中无对象
-
回收所有白色垃圾
缺点:在标记之前会 STW,确定黑白后再放开(不是没 STW 吗)
不安全的必要条件
-
白色被黑色引用
-
灰色同时丢了该白色
强弱三色不变式
-
强:不存在黑色引用白色
-
弱:被黑色引用的话,需要有灰色可达
屏障机制
-
插入屏障(仅堆空间使用)
A 引用 B 的话, B被标记为灰色(满足强不变式)
标记完以后对栈启动 STW,并进行扫描,然后清除所有的白色垃圾
-
删除屏障(Golang 没有这一步)
引用被删除的对象,被标记为灰色(满足弱不变式)
回收精度低,因为即使被删除了也可以活过这一轮
V1.8-混合写屏障(全程无 STW)
步骤
-
GC开始时将栈上可达的对象全标记为黑色(不用 STW 二次扫描)
-
栈上新建的对象为黑色(不用 STW)
-
被删除的标记为灰色
-
被添加的标记为灰色