Go pprof
参考文档
https://blog.csdn.net/EDDYCJY/article/details/124811555
原理
pprof 实现原理很简单,在内存分配释放的地方打点,并且把路径记录下来。go 会在 mallocgc 每次分配释放内存时,判断是否要采样。
web
gin 框架可以直接使用封装好的包。
import "github.com/gin-contrib/pprof"
engine := gin.Default()
pprof.Register(engine)
访问 http://localhost:port/debug/pprof/ 查看画像信息。
脚本
CPU
import "runtime/pprof"
f, err := os.Create("./cpu.pprof")
if err != nil {
fmt.Println(err)
return
}
defer f.Close()
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
StartCPUProfile、StopCPUProfile 函数可以在一段时间内持续采样并生成分析数据。
内存
import "runtime/pprof"
f, err := os.Create("mem.pprof")
if err != nil {
fmt.Println(err)
return
}
defer f.Close()
// 开始内存分析
pprof.WriteHeapProfile(f)
WriteHeapProfile 函数将当前堆内存分配的分析数据写入指定文件,不会持续采样或更新分析结果。
查看结果
进入分析
执行 go tool pprof 进入分析
# 从本地文件分析
go tool pprof cpu.pprof
go tool pprof mem.pprof
# 从远程地址分析CPU
go tool pprof http://localhost:port/debug/pprof/profile
# 从远程地址分析内存
go tool pprof http://localhost:port/debug/pprof/heap
# 自动刷新
go tool pprof -seconds=5 http://localhost:port/debug/pprof/profile
go tool pprof -seconds=5 http://localhost:port/debug/pprof/goroutine
分析命令
进入分析后,分析命令
# 查看帮助
help
# 查看资源排名
top -n 20
# 分析函数代码
list 函数名
top 结果字段讲解:
flat 函数资源消耗(运行时间或者占用内存)
flat% 函数资源占比
sum% 上面的行累加占比
cum 函数以及子函数资源消耗,大于等于 flat
cum% 函数以及子函数资源占比,大于等于 flat%
可视化分析(推荐)
无需使用命令,直观展示分析结果,需要安装 graphviz。
# 安装
# Ubuntu/Debian
sudo apt install graphviz
# CentOS
sudo yum install graphviz
# 启动可视化分析
go tool pprof -http=:8000 cpu.pprof
go tool pprof -http=:8000 -seconds=5 http://localhost:port/debug/pprof/profile
内存总是偏小?
统计内存总是偏小,原因可能有下述三种。
采样周期
采样有性能消耗,mallocgc 默认每分配满 512 kb 采样一次。Go 进程加载的时候,可以通过 GODEBUG 设置 MemProfileRate 覆盖默认值。
for p := gogetenv("GODEBUG"); p != ""; {
if key == "memprofilerate" {
if n, ok := atoi(value); ok {
MemProfileRate = n
}
} else {
// ...
}
}
MemProfileRate=1 每次分配都采样,采样全面但是非常消耗性能。
内存管理
内存管理方式存在多种差异原因:
- 内存碎片:Go 使用 tcmalloc 内存分配模型,块碎片率整体预期控制在 12.5% 左右。
- 分配但是未使用的内存:heap 上 Idle span。
- stack 内存占用。
- OS 分配但是 reserved。
- runtime 的 GC 元数据,mcache,mspan 等管理内存。
可以通过 runtime.ReadMemStats 获取详细信息。
CGO 分配的内存
这个很好理解,CGO 调用 c/c++,go 无法统计。
最后更新于