/debug/pprof/ 返回 404 是因 pprof 路由未正确注册到 http mux:用默认 mux 需确保 http.listenandserve 第二参数为 nil 以触发 _ "net/http/pprof" 的 init 注册;用自定义 mux 或 gin/echo 等框架时,必须手动挂载完整路由(含末尾斜杠),否则子路径如 /debug/pprof/goroutine 也会 404。

为什么 /debug/pprof/ 返回 404
pprof 路由没注册成功,不是服务没起来,而是 HTTP mux 没挂载对。
最常见两种情况:http.NewServeMux() 后忘了手动挂载,或用了 Gin/Echo 等框架却误以为 _ "net/http/pprof" 能自动生效。
- 用默认 mux:确保
http.ListenAndServe(":6060", nil)第二个参数是nil,否则_ "net/http/pprof"的 init 函数不会触发注册 - 用自定义 mux:必须显式添加所有子路径,尤其注意末尾斜杠 ——
/debug/pprof/和/debug/pprof是两个路由,漏掉/会导致/debug/pprof/goroutine?debug=1等子页 404 - Gin 用户别写
router.GET("/debug/pprof/*pprof", ...),pprof 内部依赖http.ServeMux的重定向逻辑,通配符会破坏它;正确做法是router.Any("/debug/pprof/*pprof", gin.WrapH(http.DefaultServeMux))
go tool pprof top 全是 runtime.mcall 或 0x456789
符号表缺失 —— profile 文件只存内存地址,没有原始二进制,pprof 就没法把地址映射回函数名。
线上或本地调试都一样:只传 URL 或只传 .pb.gz 文件,不带编译产物,top 必然不可读。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 对
go run启动的服务:先go build -o myapp .,再./myapp &,最后go tool pprof myapp http://localhost:6060/debug/pprof/profile?seconds=30 - 对
go test:用go test -cpuprofile cpu.out -o benchmark.test .,再go tool pprof benchmark.test cpu.out - 验证是否成功:进入交互模式后输
top,第一列出现main.handleRequest这类业务函数名,且占比非 100%,才算加载成功;若全是runtime.mcall或空行,说明二进制路径错、权限不足或 strip 过符号
/debug/pprof/heap inuse_space 持续上涨是不是内存泄漏
不一定。默认 /debug/pprof/heap 返回的是分配总量快照(alloc_objects),包含已被 GC 回收但尚未复用的内存,容易误判。
真正反映“存活对象”的是加 ?gc=1 参数后的采样 —— 它会强制触发一次 GC 再采集 inuse_space。
- 排查泄漏必须用
curl 'http://localhost:6060/debug/pprof/heap?gc=1' -o heap_after_gc.pb.gz - 单次结果意义有限,要对比多次:比如每 30 秒采一次,看
inuse_space是否持续增长且 GC 后不回落 - 注意
inuse_objects和inuse_space区别:前者是对象数量,后者是字节数;两者同步涨才更可疑;如果只有inuse_space涨而inuse_objects平稳,可能是大对象未释放(如缓存未清理)
Block 和 Mutex 分析为什么始终为空
pprof 默认关闭 block/mutex 采样,因为开销较大,必须显式启用。
哪怕你导入了 _ "net/http/pprof",/debug/pprof/block 和 /debug/pprof/mutex 也返回空,除非你在程序启动早期调用对应设置函数。
- 在
main()开头或 init 阶段加:runtime.SetBlockProfileRate(1)(单位:纳秒,设为 1 表示每次阻塞都采样) - 同样加:
runtime.SetMutexProfileFraction(1)(设为 1 表示每次锁竞争都记录) - 注意:这两个设置只影响后续发生的事件,已发生的阻塞/锁竞争不会补录;所以务必在服务逻辑开始前设置
- 生产环境慎用
SetBlockProfileRate(1),高并发下可能显著拖慢性能;日常排查可设为1e6(1ms 阻塞才采样)
go tool pprof 命令里有没有传对路径、HTTP 端点能不能 curl 通,再谈火焰图和 top 占比。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










