转载自 https://blog.csdn.net/liangzhiyang/article/details/52670021
请先阅读 golang 的 goroutine 调度机制 然后再到这里
golang 的垃圾回收 采用的是 标记 - 清理( Mark-and-Sweep ) 算法
就是先标记出需要回收的内存对象快,然后在清理掉;
在这里不介绍 标记和清理的具体策略(可以参考https://lengzzz.com/note/gc-in-golang),只介绍 GC 过程是怎么调度的以及 stw 相关
这个算法,会导致 stw (stop the world) 的问题,中断用户逻辑
触发 GC 机制
1. 在申 请 内存的 时 候, 检查 当前当前已分配的内存是否大于上次 GC 后的内存的 2 倍,若是 则 触 发 (主 GC 线程为当前 M )
2. 监控线程发现上次 GC 的 时间 已 经 超 过 两分 钟 了,触 发 ;将一个 G 任 务 放到全局 G 队列中去。(主 GC 线程为执行这个 G 任 务 的 M )
每当触发的时候,在主 GC 线程中就会走如下的 GC 流程:
1. stop the world ,等待所有的 M 休眠;此 时 所有的 业务逻辑 代 码 都停止
2. 标记:分配 gc 标记任务,唤醒 gcproc 个 M (就是第一步休眠的那些),分 别 做 这 个,直到所有的 M 都做完,才 结 束;并且所有 M 再次 进 入休眠
3. 清理:有一个 单 独的 goroutine 去清理已 经标记 的内存 对 象快
4. start the world , 设 置 gcwaiting=0 , 唤 醒所有的 M (不会超 过 P 个数)
对于上面的三个步骤,分别解释:
stop the world :
1. 设置 gcwaiting=1 , 这 个在每一个 G 任 务 之前会 检查 一次 这 个状 态 ,如是, 则 会将当前 M 休眠;
2.
如果
这
个
M
里面正在运行一个
长时间
的
G
任
务
,咋
办
呢,
难
道会等待
这
个
G
任
务
自己切
换吗
?
这样
的
话
可要等
10ms
啊,不能等!
坚
决不能等!
所以会主
动发
出
抢
占
标记
(
类
似于上一篇),
让
当前
G
任
务
中断,再运行下一个
G
任
务
的
时
候,就会走到第
1
步
3. 一直等待所有的 M 进入休眠,此时所有的业务逻辑代码都停 止
标记:
1. 根据 gcproc 的个数,分配成 gcproc 任 务 段; 唤 醒 gcproc-1 个 M 来 执 行(当前 M 也算一个 )
2. 对于一个 M , 唤 醒前 设置它的 helpgc 标记,唤醒之后这个 M 会立 马 判断 这 个 标记 ,如是, 则 开始做分配 给 自己的 标记 任 务,如果先做完了,就会从别的 M 里面找一些来做
3. 等每一个 M 都做完,会再次 进 入休眠
清理:
1. 通 过设 置参数,可以以一个 单 独 goroutine 运行, 这 个功能是在 1.3 版本之后增加的, 这样 的 话 就直接到下一步了,清理 过 程不是 stw 的
2. 也可以串行的在主 GC 线程执行;这样的话则 清理 过 程也是 stw 的,
start the world :
1. 设置 gcwaiting=0
2. 唤醒 P 个 M 来 继续 做 G 任 务 (此 时 没有 helpgc 标记),业务逻辑代码开 始
综上:
是基于 1.4 版本的, GC 过程在 标记过程是( STW )的
在 1.5 版本里面对 GC 做了很大的优化;采用三色标记,将标记过程细化成三段,只有前后的两段是 stw 的;极大地缩短了 gc 的 stw 时间
以上所述就是小编给大家介绍的《Golang的垃圾回收(GC)机制》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。