pprof 性能分析工具

pprof 是 Go 语言内置的性能分析工具,用于分析和优化 Go 程序的性能。它可以帮助开发者识别 CPU 瓶颈、内存泄漏、goroutine 阻塞等问题。

1. pprof 简介

pprof 提供了以下几种分析类型:

  • CPU 分析:识别消耗 CPU 时间最多的函数
  • 内存分析:识别内存分配情况
  • 阻塞分析:识别同步原语导致的阻塞
  • Goroutine 分析:查看所有 goroutine 的堆栈跟踪
  • 互斥锁分析:识别锁竞争情况
  • 线程创建分析:识别线程创建情况

2. 基本使用

2.1 导入 pprof

import _ "net/http/pprof"

只需导入这个包,它就会自动注册 HTTP 处理器到默认的 HTTP 服务上。

2.2 启动 HTTP 服务

go func() {
    log.Println(http.ListenAndServe("localhost:6060", nil))
}()

2.3 访问分析数据

启动程序后,可以通过浏览器访问:

  • http://localhost:6060/debug/pprof/ – 查看所有可用 profile
  • http://localhost:6060/debug/pprof/heap – 内存分析
  • http://localhost:6060/debug/pprof/profile?seconds=30 – CPU 分析(持续30秒)
  • http://localhost:6060/debug/pprof/block – 阻塞分析
  • http://localhost:6060/debug/pprof/goroutine?debug=2 – goroutine 分析

3. 详细使用方式

3.1 CPU 分析

采集方式:

  1. 通过 HTTP 接口:
   go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
  1. 代码中手动采集:
   f, err := os.Create("cpu.prof")
   if err != nil {
       log.Fatal(err)
   }
   pprof.StartCPUProfile(f)
   defer pprof.StopCPUProfile()

分析命令:

  • top – 查看最耗 CPU 的函数
  • list 函数名 – 查看函数的具体耗时
  • web – 生成调用图(需要安装 graphviz)

3.2 内存分析

采集方式:

  1. 通过 HTTP 接口:
   go tool pprof http://localhost:6060/debug/pprof/heap
  1. 代码中手动采集:
   f, err := os.Create("mem.prof")
   if err != nil {
       log.Fatal(err)
   }
   pprof.WriteHeapProfile(f)
   f.Close()

分析命令:

  • top – 查看内存分配最多的函数
  • top -cum – 查看累计内存分配
  • list 函数名 – 查看函数的内存分配情况
  • web – 生成内存分配图

3.3 Goroutine 分析

采集方式:

go tool pprof http://localhost:6060/debug/pprof/goroutine

分析命令:

  • top – 查看 goroutine 数量最多的调用栈
  • traces – 查看所有 goroutine 的堆栈跟踪

3.4 阻塞分析

采集方式:

go tool pprof http://localhost:6060/debug/pprof/block

分析命令:

  • top – 查看阻塞时间最长的操作

4. 高级用法

4.1 火焰图生成

  1. 安装 go-torch:
   go get github.com/uber/go-torch
  1. 生成火焰图:
   go-torch -u http://localhost:6060 -p > torch.svg

4.2 基准测试集成

在基准测试中使用 pprof:

func BenchmarkSomething(b *testing.B) {
    f, _ := os.Create("bench.prof")
    pprof.StartCPUProfile(f)
    defer pprof.StopCPUProfile()

    for i := 0; i < b.N; i++ {
        // 测试代码
    }
}

4.3 自定义分析端点

可以自定义 pprof 的 HTTP 端点:

mux := http.NewServeMux()
mux.HandleFunc("/custom/pprof/", pprof.Index)
mux.HandleFunc("/custom/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("/custom/pprof/profile", pprof.Profile)
mux.HandleFunc("/custom/pprof/symbol", pprof.Symbol)
mux.HandleFunc("/custom/pprof/trace", pprof.Trace)

5. 实际案例分析

5.1 内存泄漏分析

  1. 获取 heap profile:
   go tool pprof -http=:8080 http://localhost:6060/debug/pprof/heap
  1. 在浏览器中查看内存分配情况,重点关注持续增长的对象

5.2 CPU 热点分析

  1. 采集 30 秒 CPU profile:
   go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
  1. 使用 toplist 命令定位热点函数

6. 最佳实践

  1. 在生产环境中谨慎使用 pprof,因为它会影响性能
  2. 分析时设置合理的采样时间(通常 30-60 秒)
  3. 比较不同时间点的 profile 以识别趋势
  4. 结合日志和其他监控工具一起分析
  5. 在性能测试环境中先进行分析,再应用到生产环境

7. 注意事项

  1. pprof 默认采样频率是 100Hz(每秒100次)
  2. 内存分析显示的是分配情况,不一定是内存使用情况
  3. CPU 分析在程序繁忙时最有效
  4. 某些分析(如阻塞分析)需要先设置采样率:
   runtime.SetBlockProfileRate(1) // 每纳秒采样一次阻塞事件
滚动至顶部