Golang GC 演进之路
前言:网上关于GC 的文章错综复杂,有的文章前后混乱,自相矛盾;有的文章讲的内容较为浅显,看完以后还是一脸懵,所以花了一周时间,翻阅了大量文章,结合runtime 下的GC源码,对关于GC的知识进行了一下整理,方便以后回顾:
个人更喜欢用Notion写文章
Notion文章链接 :Gc演进之路
如有错误之处,欢迎指点。
一、标记清除算法
在golang 1.3之前的时候主要用的普通的标记-清除算法,此算法主要有以下两个步骤:
- 标记(Mark phase)
- 清除(Sweep phase)
- 具体步骤如下:
-
暂停业务逻辑(
STW),分类出可达和不可达对象,做出标记

目前程序的可达对象有:
1-2-34-7五个对象 -
开始标记,程序对所有可达的对象做上标记

对
1-2-34-7等五个可达对象做上标记 -
标记完成后,清除所有未标记对象

对象
56不可达,被GC 清除 -
关闭
STW,恢复业务程序。然后循环重复这个过程,直到Process 程序生命周期结束。
-
整个流程非常简单,但是有一点需要额外注意:mark and sweep 算法在执行的过程中,需要暂停程序!即STW(stop the word) ,STW过程中,CPU不执行代码逻辑,全部用于垃圾回收,这个过程的影响很大,所以STW也是一些回收机制最大的难题和希望优化的点。
标记清除算法缺点:
STW,让整个程序暂停,程序会出现严重卡顿- 标记需要扫描整个heap
- 清除数据会产生heap碎片
Go V1.3 变动
执行GC的基本流程首先就是启动STW,然后才进行标记清除,最后暂停STW,如下图:

从整个流程来看,全部的GC时间都是处在STW范围之内的,这样程序暂停的时间过长,影响程序的性能。所以在Go V1.3 做了简单的优化,将STW 的停止时间提前,这样能减少STW的时间范围,如图所示:

不论如何优化,这个版本的GC都会面临一个严重的问题,就是 Mark And Sweep 算法会暂停整个程序。为了面对并解决这个问题,在Go 1.5版本就采用 三色标记法 来优化这个问题。
二、三色标记法
Golang中的垃圾回收主要应用三色标记法,GC过程和其他用户goroutine可并发运行,但需要一定时间的STW,所谓的三色标记法实际上就是通过三个阶段的标记来确定需要清除的对象都有哪些。
- 具体步骤如下:
-
所有新建对象,默认都标记为白色

上图所示,我们程序可抵达的内存对象关系如左图,右边的标记表,是用来记录目前每个对象的标记颜色分类的。这里面的
程序指的是一些对象的根节点集合。所以如果我们将”程序” 展开来,会得到类似如下的表现形式:
-
每次GC回收开始,会从根节点开始遍历所有对象,把遍历到的对象全部标记为灰色(放入灰色的集合)

遍历
root根节点集合,标记可达的节点为灰色。(这里的遍历非递归遍历,只遍历一次根节点,如图所示,当前可达的对象是对象1和对象4,那么本轮遍历就结束了,对象1和对象4被标记为灰色,灰色表就会多出这两个对象) -
遍历灰色集合,将灰色对象引用的对象标记为灰色,然后将灰色对象自身标记为黑色,如图所示:

这一次遍历只扫描灰色对象,将灰色对象可直接抵达的
白色对象标记为灰色,移动到灰色表:如对象2、对象7,而之前的灰色对象1、对象4则会被标记为黑色,由灰色表移动到黑色标记表中;这一步要循环进行,直到灰色标记表中没有
灰色对象存在

重复上一步,直到灰色标记表中没有任何对象

当我们全部的可达对象都遍历后,将不再存在灰色对象,目前内存全部数据只有两种颜色,黑色和白色。黑色对象就是我们所有的可达对象,白色对象全部是不可达对象,所以白色对象就是目前内存中需要被清除的对象。
-
回收所有白色对象

将所有白色对象清除
-

最低0.47元/天 解锁文章
422

被折叠的 条评论
为什么被折叠?



