GoGC整理

引用自《Go GC 20 问》https://mp.weixin.qq.com/s/o2oMMh0PF5ZSoYD0XOBY2Q

含义

GarbageCollection 垃圾回收,一种自动内存管理机制

根集合,在GC时最先检查,包括:
全局变量
执行栈
寄存器

常见的GC方式

追踪式

标记清理:从根对象触发,标记清扫可回收的对象
标记整理:为了解决内存碎片,将对象尽可能整理到一块连续内存

增量式

标记与清扫分批进行,每次执行一小部分,增量推进,达到实时、无停顿的目的
增量整理:在增量式基础上增加对象整理过程

分代式

根据对象存活时间长短分类,时间短倾向于被回收,存活时间长的倾向于不回收

引用计数式

引用计数:引用计数值归零则立即回收

GoGC方式

无分代、不整理、并发的三色标记法

对象整理目的:

  1. 是解决内存碎片问题,但是Go给予tcmalloc分配算法,基本没有碎片问题。
    另外顺序内存分配器在多线程并不适用,整理内存队tcmalloc分配没有实质提升
  2. 分代GC目标主要是针对新创建对象,不会频繁检查所有对象。但是Go会通过逃逸分析将大部分“新生”对象存储在栈上,需要长期保存的对象存在于堆中。栈会被回收,不需要GC。
    Go的GC更专注于如何让GC和用户代码并发执行

三色标记法

核心:三色对象以及波面推进
当垃圾回收开始时,只有白色对象。随着标记过程开始进行时,灰色对象开始出现(着色),这时候波面便开始扩大。当一个对象的所有子节点均完成扫描时,会被着色为黑色。当整个堆遍历完成时,只剩下黑色和白色对象,这时的黑色对象为可达对象,即存活;而白色对象为不可达对象,即死亡。这个过程可以视为以灰色对象为波面,将黑色对象和白色对象分离,使波面不断向前推进,直到所有可达的灰色对象都变为黑色对象为止的过程。

颜色

  • 白色(可能死亡):未被回收器访问的对象,所有对象在初始状态都是白色,回收结束后,白色对象会被回收
  • 灰色(波面):已被访问的对象,但是回收器还需要队其中的指针扫描,因为可能还在指向白色对象
  • 黑色(确定存活):已被回收器访问的对象,所有字段被扫描,黑色对象指针不能直接指向白色对象

STW

是指在垃圾回收过程中为了保证实现的正确性、防止无止境的内存增长等问题而不可避免的需要停止赋值器进一步操作对象图的一段过程。

例如启动一个routine运行无限for循环,其他逻辑代码执行runtime.GC()时,会一直卡在STW阶段

如今的STW停顿时间优化在半毫秒之内了,GC进入STW时需要等待让所有用户态代码停止,但是for{}所在的routine永远“不会被中断”从而停留在STW阶段。
实践中某一个routine长时间不停止,强制拖慢STW
但是go 1.14之后,这类的goroutine可以被异步的停止

观察GC

  1. 方法1:GODEBUG=gctrace=1 ./main
    其他3个方法看文档:https://www.codercto.com/a/99611.html

有GC为什么还有内存泄漏

在GC语言中常说的内存泄漏:预期很快要被释放的内存,由于附着在长期存活的内存上、或者生命周期意外的延长,导致预计可以回收的内存无法被正常回收

  1. 预计快速释放的内存被根对象引用导致内存泄漏:例如内存被全局变量引用
  2. goroutine泄露:一个routine正常寿命周期不会释放上下文信息等。如果不停产生routine,而且不结束routine。
    另外channel链接2个不同routine如果一个g向一个没有缓冲的channel发送数据,则改groutine会被永久休眠。

并发标记清除的难点

用户态代码在回收过程中会并发更新对象,所以就有了写屏障、混合写屏障。

什么时候会破坏垃圾回收的正确性?

  1. 赋值器修改对象,导致某一个黑色对象引用了白色对象
  2. 从灰色对象出发,到达白色对象的、未经访问过的路径被赋值器破坏

只要避免任意条件,则不会出现对象丢失:

  • 条件1被避免,所有白色对象均被灰色对象引用,白色对象不会被遗漏

  • 条件2被避免,即使白色对象被写入黑色对象中,但是从灰色对象出发总存在一条没有被访问过的路径,从而找到白色对象

    在STW阶段对象赋值器触发写屏障,刷新对象。。。太复杂建议看原文。

Go 历史各个版本在 GC 方面的改进

Go 1:串行三色标记清扫
Go 1.3:并行清扫,标记过程需要 STW,停顿时间在约几百毫秒
Go 1.5:并发标记清扫,停顿时间在一百毫秒以内
Go 1.6:使用 bitmap 来记录回收内存的位置,大幅优化垃圾回收器自身消耗的内存,停顿时间在十毫秒以内
Go 1.7:停顿时间控制在两毫秒以内
Go 1.8:混合写屏障,停顿时间在半个毫秒左右
Go 1.9:彻底移除了栈的重扫描过程
Go 1.12:整合了两个阶段的 Mark Termination,但引入了一个严重的 GC Bug 至今未修(见问题 20),尚无该 Bug 对 GC 性能影响的报告
Go 1.13:着手解决向操作系统归还内存的,提出了新的 Scavenger
Go 1.14:替代了仅存活了一个版本的 scavenger,全新的页分配器,优化分配内存过程的速率与现有的扩展性问题,并引入了异步抢占,解决了由于密集循环导致的 STW 时间过长的问题
详细查看:https://www.codercto.com/a/99611.html

Go垃圾回收的API

runtime.GC:手动触发 GC
runtime.ReadMemStats:读取内存相关的统计信息,其中包含部分 GC 相关的统计信息
debug.FreeOSMemory:手动将内存归还给操作系统
debug.ReadGCStats:读取关于 GC 的相关统计信息
debug.SetGCPercent:设置 GOGC 调步变量
debug.SetMaxHeap(尚未发布):设置 Go 程序堆的上限值

GoGC如何调优

常见的GC问题

  1. 对停顿敏感,GC导致用户只需代码滞后
  2. 对资源消耗敏感,频繁分配内存应用,导致频繁垃圾回收,影响用户代码CPU利用

示例

  1. 合理化内存分配的速度、提高赋值器的 CPU 利用率,例如合理创建routine
  2. 降低并复用已经申请的内存
  3. 调整GOGC值:如果我们在遇到海量请求的时,为了避免 GC 频繁触发,可以通过将 GOGC 的值设置得更大,让 GC 触发的时间变得更晚,从而减少其触发频率

GC关注指标

  1. CPU利用率,标志回收算法会在多大程度上忒慢程序
  2. GC停顿时间,回收器会造成多长时间的停顿,STW、MarkAssist两部分
  3. GC停顿频率,STW、MarkAssist两部分
  4. GC可扩展性,堆内存变大时,回收器性能如何

如果内存分配速度超过了标记清除?

  1. 进入GC,进入并发标记阶段
  2. 并发标记会设置一个标记,并在mallocgc调用时进行检测
  3. 当存在新内存分配,会暂定分配过快的goroutine,将其转去执行一些辅助标记(Mark Assist)工作,从而达到放缓分配,辅助GC标记目的。

触发GC的时机

主动调用:runtime.GC触发,阻塞式调用等待GC运行完毕
被动触发:使用系统监控,2分钟没有产生GC则强制触发
使用步调算法,核心思想是控制内存增长比例

Go语言GC流程

1、GCMark:标记准备阶段,为并发标记做准备,启动写屏障。赋值器状态:STW
gcBgMarkPrepare
2、GCMark:扫描标记阶段,与赋值器并发执行,写屏障开启。赋值器状态:并发
gcBgMarkRootPrepare
3、GCMarkTermination:标记终止阶段,保证一个周期内标记任务完成。赋值器状态:STW
gcBgMarkTinyAllocs
4、GCoff:内存清扫阶段,将需要回收的内存还到堆中,写屏障关闭。赋值器状态:并发
gcBgMarkWorker
5、GCoff:内存归还阶段,将过多的内存还给操作系统,写屏障关闭。赋值器状态:并发
gcBgMarkDone
gcBgMarkTermination

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

推荐阅读更多精彩内容