Go pprof

对之前Go 优化的一些补充信息

基本流程

  • 在代码中添加采集相关代码
    • runtime/pprof 对于只跑一次的程序进行采集
      • import "runtime/pprof"; pprof.WriteHeapProfile(f)
    • net/http/pprof 对于在线服务,提供一个采集端口
      • import _ "net/http/pprof"; http.ListenAndServe("localhost:8000", nil)开启采集端口
  • 执行命令进行采集
    • go tool pprof main http://localhost:8000/debug/pprof/heap
    • 也可以直接用 curl 进行采集,如curl "http://localhost:8000/debug/pprof/heap">heap.pprof
  • 命令采集时会自动 dump 到文件,然后开启命令方式与该文件交互
    • /home/test/pprof/pprof.test.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz
  • 通过命令行交互方式查看已 dump 文件go tool pprof ./heap.pprof
    • tophelp
    • 可以直接把交互命令带到参数里,直接查看结果:go tool pprof -top ./heap.pprof
  • 也可以把文件传到有浏览器的机器,建立一个本地 http SVG 服务器,然后用浏览器访问图形界面http://localhost:9000/ui/来查看
    • 用浏览器访问必须先安装图形化组件: brew install graphviz
    • go tool pprof -http :9000 ./pprof.test.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz

常用概念

  • heap 分析常用参数

    • - inuse_space 默认参数,分配后未释放的内存
    • - inuse_objects 分配后未释放的对象
    • - alloc_space 总的分配内存,包含已释放的
    • - alloc_objects 总的分配的对象,包含已释放的
  • heap 常见状况

    • 存在频繁的 GC 活动,alloc_space较高而inuse_space较低
    • 内存泄漏,alloc_spaceinuse_space都较高
    • 初期创建了较大的对象、申请了较大的内存,之后一直被引用未被释放,和内存泄漏类似
  • 执行top命令时各字段含义:(对 CPU 是占用时间;对 mem 是内存容量;对 object 是对象数量)

    • flat 表示该函数自身(不包括其调用的其他函数),在采样总时间内的总消耗
    • flat% 当前函数的 flat 占程序总耗时百分比
    • sum% 当前加上前面的一行,占程序总耗时百分比
    • cum 表示该函数包括其调用的其他函数,在采样总时间内的总消耗
    • cum% 该函数加上其所有子函数,占程序总消耗百分比
    • name 函数所在包及函数名
  • http SVG 服务的视图

    • Toptop命令相同
    • Graph以树状展开图形式显示,表示函数/对象的依赖关系
      • 框越大代表开销越大
      • 箭头代表函数调用/对象依赖
    • FlameGraph火焰图,纵向是调用栈/依赖,横向是开销
      • 找到最长的栈顶开销,往往就是出问题的地方,也就是 plateaus(平顶)
    • FlameGraph new 颜色风格修改了下,更明显一点
    • PeekTop基础上增加了下面列:
      • callscalls% 调用下游函数/对象的开销
      • context 当前函数作为栈顶向下两层的栈信息,或当前对象作为栈顶,向下两层对象的信息
    • Source 可以看到各个采样点在源码中的位置

采样类型

1
2
3
4
5
6
go tool pprof http://localhost:8000/debug/pprof/profile   cpu耗时
go tool pprof http://localhost:8000/debug/pprof/heap    当前使用内存
go tool pprof http://localhost:8000/debug/pprof/allocs   分配内存,查看有 gc 相关
go tool pprof http://localhost:8000/debug/pprof/goroutine goroutine
go tool pprof http://localhost:8000/debug/pprof/mutex    锁
go tool pprof http://localhost:8000/debug/pprof/block    阻塞

使用技巧

  • 运行go tool pprof时加上--nodefration=0.05可以忽略低于5%的节点
  • top 20 -cum可指定元素数目和维度,默认 flat
  • go tool pprof --seconds 25控制采样周期
  • go tool pprof --base profile1 profile2 把 profile1 作为 base,只显示与 profile2 的差异部分

  • 对于需要尽快重启的机器,可以用下面采集脚本先收集后再分析

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #!/bin/bash
    host="localhost"
    port="8000"
    # 采集 cpu 信息
    curl "http://${host}:${port}/debug/pprof/profile">profile.pprof
    # 采集 heap 信息
    curl "http://${host}:${port}/debug/pprof/heap">heap.pprof
    # 采集内存分配信息
    curl "http://${host}:${port}/debug/pprof/allocs">allocs.pprof
    # 采集 goroutine 信息
    curl "http://${host}:${port}/debug/pprof/goroutine">goroutine.pprof
    # 采集 mutex 信息
    curl "http://${host}:${port}/debug/pprof/mutex">mutex.pprof
    # 采集 block 信息
    curl "http://${host}:${port}/debug/pprof/block">block.pprof
    

调查案例