美文网首页
go gc 分析

go gc 分析

作者: 链人成长chainerup | 来源:发表于2019-11-18 23:29 被阅读0次

    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

    相关文章

      网友评论

          本文标题:go gc 分析

          本文链接:https://www.haomeiwen.com/subject/sdqiictx.html