我们以下面的程序为例,先使用四种不同的方式来介绍如何观察 GC,并在后面的问题中通过几个详细的例子再来讨论如何优化 GC。

package mainfunc allocate() {    _ = make([]byte, 1<<20)}func main() {    for n := 1; n < 100000; n++ {        allocate()    }}

方式一:GODEBUG=gctrace=1

我们首先可以通过命令:GODEBUG=gctrace=1 ./main 来查看,如下所示:

$ go build -o main$ GODEBUG=gctrace=1 ./maingc 1 @0.000s 2%: 0.009+0.23+0.004 ms clock, 0.11+0.083/0.019/0.14+0.049 ms cpu, 4->6->2 MB, 5 MB goal, 12 Pscvg: 8 KB releasedscvg: inuse: 3, idle: 60, sys: 63, released: 57, consumed: 6 (MB)gc 2 @0.001s 2%: 0.018+1.1+0.029 ms clock, 0.22+0.047/0.074/0.048+0.34 ms cpu, 4->7->3 MB, 5 MB goal, 12 Pscvg: inuse: 3, idle: 60, sys: 63, released: 56, consumed: 7 (MB)gc 3 @0.003s 2%: 0.018+0.59+0.011 ms clock, 0.22+0.073/0.008/0.042+0.13 ms cpu, 5->6->1 MB, 6 MB goal, 12 Pscvg: 8 KB releasedscvg: inuse: 2, idle: 61, sys: 63, released: 56, consumed: 7 (MB)gc 4 @0.003s 4%: 0.019+0.70+0.054 ms clock, 0.23+0.051/0.047/0.085+0.65 ms cpu, 4->6->2 MB, 5 MB goal, 12 Pscvg: 8 KB releasedscvg: inuse: 3, idle: 60, sys: 63, released: 56, consumed: 7 (MB)scvg: 8 KB releasedscvg: inuse: 4, idle: 59, sys: 63, released: 56, consumed: 7 (MB)gc 5 @0.004s 12%: 0.021+0.26+0.49 ms clock, 0.26+0.046/0.037/0.11+5.8 ms cpu, 4->7->3 MB, 5 MB goal, 12 Pscvg: inuse: 5, idle: 58, sys: 63, released: 56, consumed: 7 (MB)gc 6 @0.005s 12%: 0.020+0.17+0.004 ms clock, 0.25+0.080/0.070/0.053+0.051 ms cpu, 5->6->1 MB, 6 MB goal, 12 Pscvg: 8 KB releasedscvg: inuse: 1, idle: 62, sys: 63, released: 56, consumed: 7 (MB)

在这个日志中可以观察到两类不同的信息:

gc 1 @0.000s 2%: 0.009+0.23+0.004 ms clock, 0.11+0.083/0.019/0.14+0.049 ms cpu, 4->6->2 MB, 5 MB goal, 12 Pgc 2 @0.001s 2%: 0.018+1.1+0.029 ms clock, 0.22+0.047/0.074/0.048+0.34 ms cpu, 4->7->3 MB, 5 MB goal, 12 P...

另外还有:

scvg: 8 KB releasedscvg: inuse: 3, idle: 60, sys: 63, released: 57, consumed: 6 (MB)scvg: inuse: 3, idle: 60, sys: 63, released: 56, consumed: 7 (MB)...

对于用户代码向运行时申请内存产生的垃圾回收:

gc 2 @0.001s 2%: 0.018+1.1+0.029 ms clock, 0.22+0.047/0.074/0.048+0.34 ms cpu, 4->7->3 MB, 5 MB goal, 12 P

含义由下表所示:

字段 含义
gc 2 第二个 GC 周期
0.001 程序开始后的 0.001 秒
2% 该 GC 周期中 CPU 的使用率
0.018 标记开始时, STW 所花费的时间(wall clock)
1.1 标记过程中,并发标记所花费的时间(wall clock)
0.029 标记终止时, STW 所花费的时间(wall clock)
0.22 标记开始时, STW 所花费的时间(cpu time)
0.047 标记过程中,标记辅助所花费的时间(cpu time)
0.074 标记过程中,并发标记所花费的时间(cpu time)
0.048 标记过程中,GC 空闲的时间(cpu time)
0.34 标记终止时, STW 所花费的时间(cpu time)
4 标记开始时,堆的大小的实际值
7 标记结束时,堆的大小的实际值
3 标记结束时,标记为存活的对象大小
5 标记结束时,堆的大小的预测值
12 P 的数量

wall clock 是指开始执行到完成所经历的实际时间,包括其他程序和本程序所消耗的时间;cpu time 是指特定程序使用 CPU 的时间;他们存在以下关系:

  • wall clock < cpu time: 充分利用多核

  • wall clock ≈ cpu time: 未并行执行

  • wall clock > cpu time: 多核优势不明显

对于运行时向操作系统申请内存产生的垃圾回收(向操作系统归还多余的内存):

scvg: 8 KB releasedscvg: inuse: 3, idle: 60, sys: 63, released: 57, consumed: 6 (MB)

含义由下表所示:

字段 含义

8KB

releasd

向操作系统归还了 8 KB 内存
3 已经分配给用户代码、正在使用的总内存大小 (MB)
60 空闲以及等待归还给操作系统的总内存大小(MB)
63 通知操作系统中保留的内存大小(MB)
57 已经归还给操作系统的(或者说还未正式申请)的内存大小(MB)
6 已经从操作系统中申请的内存大小(MB)

方式二:go tool trace

go tool trace 的主要功能是将统计而来的信息以一种可视化的方式展示给用户。要使用此工具,可以通过调用 trace API:

package mainfunc main() {    f, _ := os.Create("trace.out")    defer f.Close()    trace.Start(f)    defer trace.Stop()    (...)}

并通过执行以下命令,来启动可视化界面::

$ go tool trace trace.out2020/12/09 12:50:33 Parsing trace...2020/12/09 12:50:38 Splitting trace...2020/12/09 12:50:45 Opening browser. Trace viewer is listening on http://127.0.0.1:51839

选择第一个链接可以获得如下图示:

右上角的问号可以打开帮助菜单,主要使用方式包括:

  • w/s 键可以用于放大或者缩小视图

  • a/d 键可以用于左右移动

  • 按住 Shift 可以选取多个事件

方式三:debug.ReadGCStats

此方式可以通过代码的方式来直接实现对感兴趣指标的监控,例如我们希望每隔一秒钟监控一次 GC 的状态:

func printGCStats() {    t := time.NewTicker(time.Second)    s := debug.GCStats{}    for {        select {        case             debug.ReadGCStats(&s)            fmt.Printf("gc %d last@%v, PauseTotal %v\n", s.NumGC, s.LastGC, s.PauseTotal)        }    }}func main() {    go printGCStats()    (...)}

我们能够看到如下输出:

$ go run main.gogc 4954 last@2020-12-09 13:19:37.505575 +0100 CET, PauseTotal 29.901171msgc 9195 last@2020-12-09 13:19:38.50565 +0100 CET, PauseTotal 77.579622msgc 13502 last@2020-12-09 13:19:39.505714 +0100 CET, PauseTotal 128.022307msgc 17555 last@2020-12-09 13:19:40.505579 +0100 CET, PauseTotal 182.816528msgc 21838 last@2020-12-09 13:19:41.505595 +0100 CET, PauseTotal 246.618502ms

方式四:runtime.ReadMemStats

除了使用 debug 包提供的方法外,还可以直接通过运行时的内存相关的 API 进行监控:

func printMemStats() {    t := time.NewTicker(time.Second)    s := runtime.MemStats{}    for {        select {        case             runtime.ReadMemStats(&s)            fmt.Printf("gc %d last@%v, next_heap_size@%vMB\n", s.NumGC, time.Unix(int64(time.Duration(s.LastGC).Seconds()), 0), s.NextGC/(1<<20))        }    }}func main() {    go printMemStats()    (...)}
$ go run main.gogc 4887 last@2020-12-09 13:44:56 +0100 CET, next_heap_size@4MBgc 10049 last@2020-12-09 13:44:57 +0100 CET, next_heap_size@4MBgc 15231 last@2020-12-09 13:44:58 +0100 CET, next_heap_size@4MBgc 20378 last@2020-12-09 13:44:59 +0100 CET, next_heap_size@6MB

当然,后两种方式能够监控的指标很多,大家可以自行查看 debug.GCStats [2] 和runtime.MemStats [3] 的字段,这里不再赘述了。

以上是关于Go语言如何观察GC 的介绍,感谢您的阅读,如有疑问或意见请及时反馈给我们。


推荐文章:

Go语言中的GC(二)

0 full gc时cpu idle_Go语言中如何观察GC相关推荐

  1. 0 full gc时cpu idle_结合GC日志讲讲CMS垃圾收集器

    1 CMS垃圾收集器介绍 CMS(Concurrent Mark Sweep)收集器旨在获取最短回收停顿时间的并发垃圾收集器.CMS基于"标记-清除"算法实现,并发指的是CMS的垃 ...

  2. 在c语言中1和0的意思,!1在c语言中是什么意思?

    01 !1 是一个逻辑非表达式.感叹号!是C语言中的逻辑非运算符.C语言中的逻辑运算值是用0/1来代替的.0为假,1为真.非0值也为1.所以,!1 是一个逻辑非表达式. C语言是一门面向过程的.抽象化 ...

  3. 0 full gc时cpu idle_【cpuidle】计算每个cpu进入idle的时间

    参考内核文档 Supporting multiple CPU idle levels in kernel cpuidle sysfs System global cpuidle related inf ...

  4. c语言字符三维数组定义时赋值,c语言中三维数组的赋值顺序?

    满意答案 laoli_a 2013.06.18 采纳率:55%    等级:13 已帮助:23198人 int a[10][10][10]={0}; 10X10X10的3维数组 赋初值全部为0 for ...

  5. C语言中的空字符'\0'

    C语言中的空字符'\0' 本博客整理自: http://blog.csdn.net/suluner/article/details/54408638 https://zhidao.baidu.com/ ...

  6. asin c语言中 返回值范围_大学C语言考试易错知识点总结

    作者:cggwz 来源:https://blog.csdn.net/cggwz/article/details/103740713?utm_medium=distribute.pc_relevant. ...

  7. c语言中转义字符是由什么和什么构成,c语言中什么是转义字符

    转义字符是一种特殊的字符常量,以反斜线"\"开头,后跟一个或几个字符(数字或字母):因为它具有不同于原有字符的特定含义,故称"转义"字符. 转义字符,顾名思义, ...

  8. c语言中有关随机数的程序,C语言中随机数相关问题

    用C语言产生随机数重要用到rand函数.srand函数.及宏RAND_MAX(32767),它们均在stdlib.h中进行了声明. int rand(void);//生成一个随机数 voidsrand ...

  9. C语言中的逻辑移位和算术移位

    1.逻辑移位 左边用0补充,右边丢弃: 2.算术移位 左边用原该值的符号位填充,右边丢弃. ---------------- c语言中的移位操作符,在左移时执行的是逻辑移位,即逻辑左移,在右移时执行的 ...

最新文章

  1. 企业信息化中常见决策点应对
  2. WPF/E CTP Quick Start - 第三部分:Canvas对象(翻译)
  3. Python知识点2——列表基础
  4. 软键盘挡住WebView中输入框解决方法
  5. etcd 启动分析_Kubernetes网络分析之Flannel
  6. android 怎么换行,android textview 怎么换行?
  7. leetcode 473. Matchsticks to Square | 473. 火柴拼正方形(递归)
  8. 关于读入带空格的字符串与输入输出重定向
  9. 一文带你剖析LiteOS互斥锁Mutex源代码
  10. 差分进化算法和遗传算法 区别 谁更好
  11. 三电平igbt死区时间计算_IGBT的三电平控制原理
  12. Java集合、泛型和枚举
  13. android面试简历!Android中高级面试必知必会,内含福利
  14. 小爱同学脱离局域网远程控制开关?
  15. JavaScript实现图片瀑布流
  16. 刘小乐教授:我与生物信息学的不解之缘
  17. 深入理解安卓异步任务AsyncTask
  18. Failed to parse mapping resource
  19. Android Studio Git教程
  20. java多态app_Java 入门教程 - Java 多态 - IT学院 - 中国软件协会智能应用服务分会...

热门文章

  1. 笔记:windows 2012 安装SQL 2008 群集报错
  2. DXP 内电层分割
  3. android通过json生成视图
  4. 当 Egg 遇到 TypeScript,收获茶叶蛋一枚 #27
  5. Centos 监控进程,并自动重启
  6. DreamFacotry 第6章 将业务逻辑集成到DreamFactory API中
  7. Oracle备份与恢复 关于expdp导出远程数据到本地的使用
  8. ZooKeeper:分布式应用程序的分布式协调服务
  9. 通过Grafana访问Mysql/MariaDB -- Web端数据库管理、分析、可视化工具
  10. java properties文件 安全_java 数据库读取工具类(读取config.properties配置文件)[包含线程安全] | 学步园...