GC触发的条件
src/runtime/proc.go:forcegcperiodruntime.gc()
v1.3版本 标记清除法
第一步,找出不可达的对象,做上标记。
第二部,回收没有被标记的对象。
缺点:在标记的时候会进行STW(Stop the world)
Stop the world
设置gcwaiting=1,这个在每一个G任务之前会检查一次这个状态,如是,则会将当前M 休眠;
如果这个M里面正在运行一个长时间的G任务,咋办呢,难道会等待这个G任务自己切换吗?这样的话可要等10ms啊,不能等!坚决不能等! 所以会主动发出抢占标记(类似于上一篇),让当前G任务中断,再运行下一个G任务的时候,就会走到第1步
一直等待所有的M进入休眠,此时所有的业务逻辑代码都停止
v1.5版本 三色标记法
-
启动STW
-
新创建的对象默认颜色是白色
-
GC回收从根节点一次遍历所有对象,把遍历到的对象从白色集合放入灰色集合。
-
循环遍历灰色集合,将灰色对象引用的对象从白色集合放入灰色集合,之后将此灰色对象放入黑色集合,直到灰色中无任何对象
-
停止STW
-
回收所有的白色标记表的对象.也就是回收没有被引用的对象(垃圾)。
清除操作和用户逻辑可以并发。
v1.8版本 混合写屏障机制(hybrid write barrier)
写屏障
该屏障之前的写操作和之后的写操作相比,先被系统其它组件感知。 通俗的讲:就是在gc跑的过程中,可以监控对象的内存修改,并对对象进行重新标记。(实际上也是超短暂的stw,然后对对象进行标记)
总结:创建对象还是对象的引用改变,都会先变为灰色
步骤
-
扫描栈中内存对象全部标记黑色,对新增加的对象标记为黑色
-
扫描堆中的全部对象,把遍历到的对象从白色集合放入灰色集合。
-
循环遍历灰色集合,将灰色对象引用的对象从白色集合放入灰色集合,之后将此灰色对象放入黑色集合,直到灰色中无任何对象,对重新引用的对象标记为灰色,对被添加的对象标记为灰色。
-
回收所有的白色标记表的对象.也就是回收垃圾。
优化的点:标记操作和用户逻辑也是并发的,用户逻辑会时常生成对象或者改变对象的引用,那么标记和用户逻辑如何并发呢?因为用户逻辑在会存在创建新的对象和改变对象引用的情况,所以写屏障机制会把新的对象都会先变为灰色。