Go语言内置的pprof工具是排查程序性能问题的核心工具,它可以帮助开发者采集CPU、内存、 goroutine等多维度的运行时数据,定位程序中的性能瓶颈。很多开发者在使用pprof时会遇到采集到的分析结果中部分方法缺失,同时也不清楚各类指标的实际含义,导致无法有效完成性能优化工作。
pprof基础使用方式
Go的pprof分为运行时采集和离线分析两部分,常用的采集方式有两种,一种是通过net/http/pprof包在程序中开启HTTP服务,另一种是程序退出时生成pprof文件。下面是开启HTTP采集服务的示例代码:
package main
import (
"net/http"
_ "net/http/pprof"
)
func main() {
// 启动pprof HTTP服务,默认监听在6060端口
http.ListenAndServe("localhost:6060", nil)
}
开启服务后,可以通过访问对应端点获取不同类型的性能数据,比如访问/debug/pprof/profile获取CPU采样数据,访问/debug/pprof/heap获取内存分配数据。拿到数据后可以使用go tool pprof命令进行本地分析。
pprof方法缺失的常见原因
很多开发者会发现采集到的pprof结果中,部分自己编写的方法没有出现在分析结果里,或者方法名显示为未知符号,主要有以下几种原因:
- 编译时未保留符号表:如果使用-ldflags "-s -w"参数编译程序,会去掉符号表和调试信息,pprof无法关联到具体的方法名,导致方法缺失。
- 方法执行时间过短:CPU采样默认是每10ms采样一次,如果某个方法的单次执行时间远小于10ms,且整体占用CPU比例极低,就不会被采样到,自然不会出现在结果中。
- 采样时长不足:如果采集CPU数据的时长设置过短,比如只有1秒,很多低频率执行的方法还没被采样到,程序就结束了采集过程。
- 内联优化导致方法被合并:Go编译器默认会开启内联优化,小方法会被直接嵌入到调用方的方法中,pprof采样时会显示为调用方的方法,看不到被内联的原方法。
pprof结果的核心指标解读
不同类型的pprof结果对应不同的指标,下面分别介绍CPU分析和内存分析的核心指标含义:
CPU分析结果解读
CPU分析的结果主要展示各个方法占用CPU的时间,常用的查看命令是top,输出的结果包含以下几列:
| 列名 | 含义 |
|---|---|
| flat | 当前方法自身执行占用的CPU时间,不包含调用其他方法的时间 |
| flat% | 当前方法自身占用CPU时间占总采样时间的百分比 |
| sum% | 当前行以及之前所有行的flat%累加值 |
| cum | 当前方法以及它调用的所有子方法占用的CPU总时间 |
| cum% | 当前方法的cum时间占总采样时间的百分比 |
如果某个方法的cum占比较高,说明它或者它调用的子方法存在性能问题,需要进一步查看调用链定位具体问题。
内存分析结果解读
内存分析的结果主要展示内存的分配情况,同样可以用top命令查看,核心指标如下:
- flat:当前方法自身分配的内存大小,不包含调用其他方法分配的内存。
- cum:当前方法以及它调用的所有子方法分配的总内存大小。
- alloc_objects:当前方法分配的对象总数。
- alloc_space:当前方法分配的内存总大小。
如果某个方法的alloc_space占比较高,说明这个方法的内存分配比较频繁或者单次分配内存过大,需要考虑是否有不必要的内存分配,比如是否可以复用对象减少临时对象的创建。
解决pprof方法缺失的实操方案
针对前面提到的方法缺失原因,可以采取对应的解决措施:
调整编译参数
如果需要保留符号表方便pprof分析,编译时不要使用-s -w参数,如果已经使用了这两个参数,可以去掉后重新编译程序,再采集pprof数据。正确的编译命令示例如下:
# 保留符号表的编译命令,不要加-ldflags "-s -w" go build -o main main.go
调整采样参数
如果是因为方法执行时间短没有被采样到,可以适当延长CPU采样时间,默认CPU采样时长是30秒,可以通过参数调整,比如设置为60秒:
# 采集60秒的CPU数据 go tool pprof -seconds 60 http://localhost:6060/debug/pprof/profile
关闭内联优化
如果希望看到被内联的小方法,可以在编译时关闭内联优化,命令如下:
# 关闭内联优化编译程序 go build -gcflags="-l" -o main main.go
关闭内联后,小方法不会被嵌入到调用方中,pprof就可以单独采集到这些方法的运行数据,不过关闭内联会对程序性能有一定影响,仅建议用于调试阶段。
总结
pprof是Go性能分析的核心工具,遇到方法缺失问题时,可以先从编译参数、采样时长、内联优化这几个方向排查原因,调整对应的配置后重新采集数据即可解决。解读pprof结果时,需要根据不同的分析类型关注对应的核心指标,CPU分析重点看cum和flat的占比,内存分析重点看alloc_space和alloc_objects的数值,结合调用链视图可以快速定位到性能瓶颈的具体位置,完成程序的性能优化工作。