Golang的分代GC(Garbage Collection)

前言

Go语言的垃圾回收(Garbage Collection,以下简称GC)机制是并发三色标记,是一种不移动的标记-清扫 GC算法。在2018年的一次演讲 中,官方公布了尝试使用分代GC的想法。截止目前(2019年4月份),分代GC仍处于试验的状态,没有具体的发布时间。
go官方代码库,目前共有10个commit,本文主要讲解Go分代GC的实现思路以及现有的一些问题,后面可能详细讲解一下代码。

标记-清扫 GC算法

标记-清扫GC算法首先会从一些固定的root节点开始,对于Go语言来说就是全局指针和 goroutine 栈上的指针,根据这些root节点进行递归标记。当标记完成后,所有被标记的对象就都是存活的,其余的对象即是可以清扫的。


file

分代GC算法

分代GC是基于这样一个假设:大部分新分配的对象存活周期较短,在分配后的第一轮GC中就会被回收掉。
如果这个假设成立,那么GC期间只去扫描和清扫新分配的对象就可以清扫掉大部分需要回收的对象,这样就可以节省GC的时间。
补充几个概念:
新生代对象:上一轮GC后新分配的对象。
老年代对象:上一轮GC中存活的对象。
Minor GC:小型GC,只对新生代对象进行清扫。
Major GC:大型GC,清扫所有对象,因为一直进行Minor GC的话,会造成程序占用的内存越来越多,老年代对象越来越多,所以在分代GC中要穿插使用Minor GC和Major GC,Major GC可以是标记-清扫GC算法或复制GC算法,一般是和复制GC算法配合使用(容易区分新生代对象和老年代对象)。

这里额外说一下,在GC中有两种问题:一种是本不该被清扫的对象被清扫了,这种会造成程序错误。 另一种是本该被清扫的对象没有被清扫,这种会增加内存的占用量,但不会造成程序错误。 分代GC属于第二种问题。

Go分代GC的实现思路

Go将分代GC算法与标记清扫算法相结合,实现了一个不移动的分代GC。那么如何判别新生代和老年代呢?

首先来看下Go并发标记清扫算法是如何工作的

file

allocBits 内存分配标志位,表示这一小块内存已经分配了对象。 gcmarkBits GC清扫标志位,表示这一小块内存在本轮GC中是存活的对象,不能被清扫。

  • 程序第一次运行期间,在1、2、4、5、6位置分配了新对象(allocBits 有所体现)
  • 开始GC时,1、4、5位置的对象是存活的(gcmarkBits 有所体现)
  • 完成GC时,将gcmarkBits的值赋给allocBits,然后清空gcmarkBits。表示1、4、5位置已经分配了对象,不能重复分配。
  • 下一轮程序运行期间,又在2、3、6位置分配了新对象…………

如何实现的不移动的分代GC?

在上图中可以看出,在每次GC完成期间,都对gcmarkBits进行了清空操作,如果不进行清空操作,会发生什么?

image.png

如果在GC期间,发现了一个对象的allocBit=1,且还没有进行标记的情况下gcmarkBit=1,那么就说明这个对象时上一轮GC中存活的老年代对象(对象的gcmarkBit是在上一轮GC期间被标记的) ;如果一个对象的allocBit=1gcmarkBit=0,这个对象是在这一轮程序运行期间分配的新生代对象。

所以allocBit=1 && gcmarkBit=1表示老年代对象,allocBit=1 && gcmarkBit=0表示新生代对象,这样就实现在可不增加额外工作量的情况下,判别新生代和老年代对象。 如果每轮GC都对所有对象进行扫描去判断是否是新生代对象,是否存活,那么分代GC的优势将不再存在,如何做到减小分代GC的工作量呢?
一种方案是在程序运行期间也开启一个类似writrbarrier(写屏障)的机制,使用一个快速写屏障,这种方案会对GC关闭期间程序的运行速度造成一些影响,另外一种方案就是Go分代GC的另外一个创新点,使用card hash消除在GC关闭期间的写屏障。

为什么要判别老年代对象和新生代对象?

一个是因为在Minor GC中只需要对新生代对象进行清扫,老年代对象无论是否标记可达,都认为是存活的,不会进行清扫。另外一个是因为要找出老年代对象对新生代对象的指向,对新生代对象进行提升的操作。
分代GC中Minor GC不会清空gcmarkBits,Go语言的标记-清扫GC是根据根节点递归扫描,如果对象已经被标记了,就会返回,不再递归扫描下去。那么在扫描过程中,遇到老年代对象就会立即返回,如果这个老年代对象是一个指针,并且在程序运行期间指向了一个新生代对象,并且这个老年代对象仍是存活的(标记可达的),那么就会遗漏对这个老年代对象所指向的新生代对象的标记,造成这个新生代被回收掉,造成程序的错误。所以在分代GC中也会把老年代对象作为一个根节点,找出老年代指向的新生代对象,对新生代对象进行提升标记操作。

使用Hash进行加速

file

将内存每1KB空间分成一个cardcardhash表示对card中所有老年代指针对象进行hash计算的结果,Cardhash Table存储所有cardcardhash。 在GC期间会重新计算每个card中老年代指针对象的hash值,如果这个老年代在程序运行期间指向了新对象,那么重新计算hash时,就会发现其所在的card与上一次GC时计算的hash值不相符,再去仔细扫描这个card中老年代所指向的新生代对象,将新生代对象进行提升为老年代的操作。
仔细扫描提升的时间比hash更耗时,且大部分的card的hash值与之前的值是相同的,所以加入hash计算可以达到加速的目的。

End

这篇文章就讲到这里吧,Go的分代GC目前还有些问题,Hash没有想象中的快,所以在某些情况下,没有很大的性能提升,甚至在某些特定情况下还可能造成性能下降。下次可能会讲下代码级别的具体实现。希望Go早日能够将分代GC合入分支,带来更好的性能。
欢迎交流,如有错误,还请指出。
转载请注明出处,谢谢。
Go是如何穿插使用Minor GC和Major GC已经在下一篇文章更新,欢迎阅读。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容