Go 垃圾回收使用的是标记-回收算法,分为四个阶段:标记准备阶段,标记阶段,标记终止阶段,清理阶段。
进行的操作:
标记协程的启动数量?
每个逻辑处理器P会启动一个标记协程,但并不是每个标记协程都会执行,同时执行的标记协程数量大约是P的25%,也就是有25%的CPU用在GC上。例如,有4个P,那同一时间只有1个标记协程在执行。这样做可以减少GC给用户程序带来的影响。
[代码:runtime/mgc.go.startCycle()]
标记协程的调度过程?
STW后,重新启动所有协程,调度器会进行新的一轮调度,这时会判断程序是否处于GC阶段,如果是则判断是否需要执行标记任务。怎么判断呢?分两种情况:
第一种,需要执行的标记协程数(dedicatedMarkWorkersNeeded)大于0时,此时是DedicatedMode模式;
第二种,fractionalUtilizationGoal大于0且当前P执行标记任务的时间小于fractionalUtilizationGoal*当前标记周期的时间,这种情况只会占用部分时间来进行标记任务,超出时间后,其它协程可以抢占,此时是FractionalMode模式。
[代码:runtime/mgc.go.findRunnableGCWorker()]
为什么要开启写屏障?
因为用户协程和标记协程是并发执行的,在标记的过程中,函数栈内可能会有新分配的对象,如果没有开启写屏障,那新分配的对象是标记为白色的,可能会在这次GC中被误回收。写屏障的作用就是把新分配的对象标记为灰色,避免误回收,这些灰色对象会在下次GC中判断是否需要回收。
根对象包含什么?
根对象包含了全局对象、栈对象(goroutine栈)
进行的操作:
标记任务的模式有哪些?
1、DedicatedMode:代表当前P专门负责标记对象,不会被抢占;
2、FractionalMode:在标记任务到达目标时间后,会自动退出;
3、IdleMode:当前P没有可以执行的G,执行标记任务,直到被抢占;
在DedicateMode模式中,协程不能被抢占,那这个P中的G将得不到执行,怎么办呢?
先执行可以被抢占的标记协程,如果标记协程已经被抢占了,则将当前P中的G挪到全局队列中,进入不能被抢占的模式
黑色对象:对象已被标记,包含的子对象也被标记,不会在本次GC中回收
灰色对象:对象已被标记,但包含的子对象尚未标记,不会在本次GC中回收
白色对象:对象未标记,会在本次GC中回收
三色标记法用是否可达来判断对象是否存活,首先会扫描根对象,将根对象引用的对象标记为灰色;然后处理灰色对象,将灰色对象引用的对象标记为灰色,自身标记为黑色,循环处理灰色对象,直到灰色对象集合为空,此时只剩黑色对象和白色对象
进行的操作:
进行的操作:
浅析 Golang 垃圾回收机制
深入理解Go-垃圾回收机制
《Go 语言底层原理剖析》 - 郑建勋