go gc 分析

1 先翻译一下runtime 文档中,关于gc的内容(里面涉及GC日志格式)

···
原文: https://golang.org/pkg/runtime/
翻译参考: https://colobu.com/2016/07/04/dive-into-go-11/#pprof

···

allocfreetrace: 设置 allocfreetrace=1 会监控每次分配,但因每次分配和释放的栈信息(stack trace)

cgocheck: 设置 cgocheck=0 禁用所有cgo检查将Go指针传递给非Go代码是否正确。
cgocheck=1 (缺省值) 轻量级检查。cgocheck=2 重量级检查。

efence: 设置 efence=1 导致分配器 allocator将每个对象分配在一个唯一的页page上,地址不重用。

gccheckmark: 设置 gccheckmark=1 允许垃圾回收器执行并发mark阶段的校验。会导致Stop The World。

gcpacertrace: 设置 gcpacertrace=1 会让来几回收器打印出concurrent pacer的内部状态。

gcshrinkstackoff: 设置 gcshrinkstackoff=1 则禁止将 goroutines 的栈缩小为更小栈。

gcstackbarrieroff: 设置 gcstackbarrieroff=1 禁用stack barriers,会影响垃圾回收器的重复搜索栈的功能。

gcstackbarrierall: 设置 gcstackbarrierall=1 会为每个栈帧安装一 stack barriers。

gcstoptheworld: 设置 gcstoptheworld=1 则禁用并发垃圾回收,每次回收都会触发STW。设置gcstoptheworld=2则禁用垃圾回收后的concurrent sweeping。

gctrace: 设置 gctrace=1导致每次垃圾回收器触发一行日志,包含内存回收的概要信息和暂停的时间。设置gctrace=2起同样的效果,but also repeats each collection。格式如下:

gc # @#s #%: #+#+# ms clock, #+#/#/#+# ms cpu, #->#-># MB, # MB goal, # P

where the fields are as follows:
gc # GC id,每次GC加一
@#s 程序启动后的时间,单位秒
#% 程序启动后GC所用的时间比
#+...+# 此次GC所用的wall-clock/CPU时间
#->#-># MB GC开始时的堆大小, GC结束时的堆大小, 活着的(live)堆大小
# MB goal 总的堆大小
# P CPU使用数
垃圾回收分为下面的几个阶段:stop-the-world (STW) sweep termination, concurrent
mark and scan, and STW mark termination。 mark/scan的CPU时间又分为 assist time (GC performed in
line with allocation), background GC time, and idle GC time。

垃圾回收的四个阶段:
Sweep Termination: 对未清扫的span进行清扫, 只有上一轮的GC的清扫工作完成才可以开始新一轮的GC
Mark: 扫描所有根对象, 和根对象可以到达的所有对象, 标记它们不被回收
Mark Termination: 完成标记工作, 重新扫描部分根对象(要求STW)
Sweep: 按标记结果清扫span

如果日志后以"(forced)"结尾,则GC通过runtime.GC()调用执行,此时所有的阶段都是STW.

memprofilerate: 设置 memprofilerate=X 会更新runtime.MemProfileRate的值。0则禁用这个profie。

invalidptr: 默认设为invalidptr=1, 如果指针被赋予一个无效值,会引起程序的崩溃,设置该值为0,会停止该检查,
0只能临时用于查找bug,真正的解决方法是不要把整数类型的值存在指针变量里面。

sbrk: 设置 sbrk=1 会使用实验性的实现替换memory allocator 和 garbage collector。

scavenge: scavenge=1 允许heap scavenger的debug模式。

scheddetail: 设置 schedtrace=X 和 scheddetail=1 会导致goroutine调度器每个X毫秒输出多行调度信息。

schedtrace: 设置 schedtrace=X导致调度器每个X秒输出一行调度器的概要信息。

2 GC 触发时机

gcTriggerHeap: 当前分配的内存达到一定值就触发GC
gcTriggerTime: 当一定时间没有执行过GC就触发GC
gcTriggerCycle: 要求启动新一轮的GC, 已启动则跳过, 手动触发GC的runtime.GC()会使用这个条件

3 gc 具体的过程

3.1 根对象

在GC的标记阶段首先需要标记的就是"根对象", 从根对象开始可到达的所有对象都会被认为是存活的.
根对象包含了全局变量, 各个G的栈上的变量等, GC会先扫描根对象然后再扫描根对象可到达的所有对象.

3.2 三色标记过程

之前自己整理的 https://www.jianshu.com/p/ebf03d9605d0

4 gc 优化案例

4.1 减少分配对象数量(这样就减少了扫描时间)

链接:https://www.zhihu.com/question/21615032/answer/18781477

4.2 一个检测G 长时间占用CPU时间片,导致GC hang住的排查工具

https://github.com/zhanglvmeng/go-tool-trace-greediest-goroutines

4.3 【已验证】io.copybuffer 没传buffer进去,底层自动创建了多个buffer对象,造成内存泄漏,频繁gc。

https://my.oschina.net/u/2950272/blog/1788299

4.4 使用array 替代 map, 减少扫描时间

https://studygolang.com/articles/1720

4.5 多个不同维度的分析

http://guileen.github.io/2016/06/15/how-did-i-optimize-golang-gc/

4.6 减少GC的一些思路

http://www.philo.top/2015/05/29/golangProfilingAndGC2/

4.7 GC排查的步骤

http://xiaorui.cc/2016/03/20/golang%E4%BD%BF%E7%94%A8pprof%E7%9B%91%E6%8E%A7%E6%80%A7%E8%83%BD%E5%8F%8Agc%E8%B0%83%E4%BC%98/

4.8 string 以及[]byte 的GC问题

https://www.520mwx.com/view/35045

5 gc 查看工具

gcvis https://github.com/davecheney/gcvis
参考自 https://colobu.com/2016/07/04/dive-into-go-11/#pprof

6 GC 监控

对于线上GC的监控,基本上读取runtime.MemStats结构中的内容,然后存储到时序数据库中。具体有如下两种获取方式:

// 方式1
memStats := &runtime.MemStats{}
runtime.ReadMemStats(memStats)

// 方式2 json格式
expvar.Get("memstats").String()

7 scavenger

到目前为止,gctrace给出的最有用的信息就是 the heap scavenger的输出.

scvg143: inuse: 8, idle: 104, sys: 113, released: 104, consumed: 8 (MB)

scvg143 表示第143次输出。其他字段,见下图。

scvg.png

图片来源于https://colobu.com/2016/07/04/dive-into-go-11/#pprof

scavenger 的工作就是周期性地打扫heap中无用的操作系统内存分页, 它会向操作系统发出建义,请操作系统回收无用内存页,

当然并不能强迫操作系统立刻就去做回收处理,操作系统可以忽略此建义,或是延迟回收,比如直到可分配的空闲内存不够的时候。

scavenger输出的信息是我们了解go程序虚拟内存空间使用情况的最好方式, 当然你也可以通过其它工具,如free, top来获到这些信息,
不过你应用信任scavenger.

8 参考文献

讲的很好,概述性:https://xenojoshua.com/2019/03/golang-memory/#31-%E7%89%88%E6%9C%AC%E5%8E%86%E5%8F%B2--%E6%BC%94%E8%BF%9B

非常详细的文章https://yq.aliyun.com/blog/573819
gc 线上监控: http://kuring.me/post/golang-gc/

scavenger: https://studygolang.com/articles/6346

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

推荐阅读更多精彩内容