摘抄:golang pprof实用使用指南

注册接口

第一步,在引用中加上

1
2
"net/http"
_ "net/http/pprof"

第二步,在代码开始运行的地方加上

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

接着,我们访问http://127.0.0.1:6060/debug/pprof/,即可看到

  • allocs:查看过去所有内存分配的样本。
  • block:查看导致阻塞同步的堆栈跟踪。
  • cmdline: 当前程序的命令行的完整调用路径。
  • goroutine:查看当前所有运行的 goroutines 堆栈跟踪。
  • heap:查看活动对象的内存分配情况。
  • mutex:查看导致互斥锁的竞争持有者的堆栈跟踪。
  • profile: 默认进行 30s 的 CPU Profiling,得到一个分析用的 profile 文件。
  • threadcreate:查看创建新 OS 线程的堆栈跟踪。
  • trace:mp.weixin.qq.com/s/I9xSMxy32…

注意,默认情况下是不追踪block和mutex的信息的,如果想要看这两个信息,需要在代码中加上两行:

1
2
runtime.SetBlockProfileRate(1) // 开启对阻塞操作的跟踪,block  
runtime.SetMutexProfileFraction(1) // 开启对锁调用的跟踪,mutex

注意,上文的所有信息都是实时的,如果你刷新一下,是可以看到数字在变化的。此时如果点击蓝色的连接,可以看到一些协程的栈信息,这些信息并不容易阅读。如果想要更加清晰的数据,需要将信息保存下来,在本地进行分析。


给服务都注册上没问题,但是最好还是加个中间件控制一下访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package main

import (
"net/http"
"net/http/pprof"

"github.com/gin-gonic/gin"
)

const (
AllowPprof = true
)

func AccessControl(c *gin.Context) {
if AllowPprof {
c.Next()
return
}
c.Next()
}

func main() {
bizApp := gin.Default()

bizApp.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "Hello, World!",
})
})

pprofApp := gin.Default()
pprofApp.Use(AccessControl)
pprofApp.GET("/debug/pprof/", gin.WrapH(http.HandlerFunc(pprof.Index)))
pprofApp.GET("/debug/pprof/allocs", gin.WrapH(pprof.Handler("allocs")))
pprofApp.GET("/debug/pprof/block", gin.WrapH(pprof.Handler("block")))
pprofApp.GET("/debug/pprof/goroutine", gin.WrapH(pprof.Handler("goroutine")))
pprofApp.GET("/debug/pprof/heap", gin.WrapH(pprof.Handler("heap")))
pprofApp.GET("/debug/pprof/mutex", gin.WrapH(pprof.Handler("mutex")))
pprofApp.GET("/debug/pprof/threadcreate", gin.WrapH(pprof.Handler("threadcreate")))
pprofApp.GET("/debug/pprof/cmdline", gin.WrapH(http.HandlerFunc(pprof.Cmdline)))
pprofApp.GET("/debug/pprof/profile", gin.WrapH(http.HandlerFunc(pprof.Profile)))
pprofApp.GET("/debug/pprof/symbol", gin.WrapH(http.HandlerFunc(pprof.Symbol)))
pprofApp.GET("/debug/pprof/trace", gin.WrapH(http.HandlerFunc(pprof.Trace)))
go func() {
pprofApp.Run(":8081")
}()

bizApp.Run(":8080")
}




采集&分析数据

有两种方式下载信息

方法一(推荐):

直接运行go tool pprof http://localhost:6060/debug/pprof/XXX,其会自动下载数据到本地,然后供你分析。

实践:

1
2
3
4
5
6
7
8
❯ go tool pprof http://10.251.179.31:9202/debug/pprof/heap
Fetching profile over HTTP from http://10.251.179.31:9202/debug/pprof/heap
Saved profile in /Users/g****ng/pprof/pprof.logic_core.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz
File: logic_core
Type: inuse_space
Time: 2025-08-28 22:07:21 CST
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)

方法二:

访问http://localhost:6060/debug/pprof/xxx,浏览器就会提醒你下载文件。

这里有一个小点要注意,在这个页面下,点击profiletrace总是会下载文件。而点击其他链接会跳转到另一个页面,来展示一些数据,但是可读性也比较差。

如果点击profile,程序会开始进行半分钟(默认值)的CPU采样,然后才会下载文件。

在跳转到页面中,会发现URL带有?debug=1的后缀,如果把这个后缀去掉,则也会提示你下载文件

1
curl http://localhost:9591/debug/pprof/goroutine -o goroutine-pprof
1
go tool pprof -http=:8000 cpu.pprof




注意事项

OOM

当发生OOM的时候,拉取到heap文件后渲染,需要设置一下采样范围为"已分配",而不是"inused"

image-20260211093829337