其他分享
首页 > 其他分享> > Golang 垃圾回收

Golang 垃圾回收

作者:互联网

Go 垃圾回收使用的是标记-回收算法,分为四个阶段:标记准备阶段,标记阶段,标记终止阶段,清理阶段。

一、垃圾回收流程

image

1)标记准备阶段

进行的操作:

标记协程的启动数量?
每个逻辑处理器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栈)

2)标记阶段

进行的操作:

标记任务的模式有哪些?
1、DedicatedMode:代表当前P专门负责标记对象,不会被抢占;
2、FractionalMode:在标记任务到达目标时间后,会自动退出;
3、IdleMode:当前P没有可以执行的G,执行标记任务,直到被抢占;

在DedicateMode模式中,协程不能被抢占,那这个P中的G将得不到执行,怎么办呢?
先执行可以被抢占的标记协程,如果标记协程已经被抢占了,则将当前P中的G挪到全局队列中,进入不能被抢占的模式

三色标记法:

黑色对象:对象已被标记,包含的子对象也被标记,不会在本次GC中回收
灰色对象:对象已被标记,但包含的子对象尚未标记,不会在本次GC中回收
白色对象:对象未标记,会在本次GC中回收

image

三色标记法用是否可达来判断对象是否存活,首先会扫描根对象,将根对象引用的对象标记为灰色;然后处理灰色对象,将灰色对象引用的对象标记为灰色,自身标记为黑色,循环处理灰色对象,直到灰色对象集合为空,此时只剩黑色对象和白色对象

3)标记终止阶段

进行的操作:

4)清理阶段

进行的操作:

二、垃圾回收触发时机

  1. 内存分配量达到阈值:每次内存分配都会判断当前内存是否达到阈值,如果是则触发GC。阈值为当前堆内存达到2倍上一次GC后的内存,2倍为内存增长率,可通过环节变量GOGC调整;
  2. 定时触发:默认2分钟触发一次,这个配置在runtime/proc.go里的forcegcperiod参数;
  3. 手动触发:使用runtime.GC() 手动触发;

浅析 Golang 垃圾回收机制
深入理解Go-垃圾回收机制
《Go 语言底层原理剖析》 - 郑建勋

标签:协程,标记,对象,回收,Golang,GC,垃圾,抢占
来源: https://www.cnblogs.com/xiao-yu-zhu/p/16177170.html