pprof默认不启用http接口,必须显式导入_ "net/http/pprof"(触发init注册到defaultservemux)或手动挂载handler;若用fiber等框架需独立启动pprof服务并确保gc触发与符号表可用。

pprof 默认只在 debug 模式下启用 HTTP 接口
Go 程序默认不暴露 /debug/pprof 路由,除非你显式注册了它,或者用了 net/http/pprof 包。很多人跑完程序却打不开 http://localhost:6060/debug/pprof/,第一反应是“pprof 坏了”,其实是没加这行:
import _ "net/http/pprof"
注意是下划线导入,它会自动注册 handler 到默认的 http.DefaultServeMux。如果你用了自定义的 http.ServeMux,得手动调用:
pprof.Handler("profile").ServeHTTP(w, r)
常见坑:
- 忘记 import,接口 404
- 启动了 HTTP server 但没监听
:6060(或被其他端口占用) - 程序是短生命周期的命令行工具,还没来得及访问就退出了
如何采集 CPU 和内存 profile 数据
pprof 提供两类最常用 profile:cpu 和 heap,获取方式不同:
-
curl -o cpu.pprof http://localhost:6060/debug/pprof/profile?seconds=30—— 默认采样 30 秒 CPU 使用,阻塞请求 -
curl -o heap.pprof http://localhost:6060/debug/pprof/heap—— 立即抓取当前堆快照(allocs 对应累计分配量)
注意:profile 是唯一支持 ?seconds= 参数的 endpoint;heap、goroutine、block 都是即时快照。采样时间太短(如 ?seconds=1)可能导致数据稀疏,看不出热点。
如果程序没开 HTTP server,也可以用 runtime API 直接写文件:
pprof.WriteHeapProfile(f)
但这样拿不到 goroutine 栈和 symbol 信息,调试价值低。
go tool pprof 命令行怎么快速定位瓶颈
拿到 cpu.pprof 后,别急着打开 Web 界面。先用命令行快速筛一遍:
go tool pprof cpu.pprof
进入交互模式后,常用命令:
-
top10—— 显示耗时最多的 10 个函数(flat 时间) -
web—— 生成 SVG 调用图(需系统装 graphviz) -
list main.Run—— 查看某个函数的源码级行号耗时分布 -
peek fmt.Sprintf—— 查看谁在频繁调用fmt.Sprintf
关键点:默认显示的是 flat(函数自身执行时间),不是 cum(包含子调用)。真正卡住的往往是 flat 高的函数,比如一个没缓存的 JSON 序列化循环。
如果看到大量 runtime.mallocgc 占比高,说明内存分配频繁,接着查 heap.pprof 的 inuse_space 或 alloc_objects。
HTTP 服务中 goroutine 泄漏怎么确认
当服务响应变慢、连接堆积,先看 /debug/pprof/goroutine?debug=2(带栈帧的完整列表),而不是 ?debug=1(只统计数量)。
更高效的方式是对比两次快照:
curl 'http://localhost:6060/debug/pprof/goroutine?debug=2' > g1.txt<br>sleep 10<br>curl 'http://localhost:6060/debug/pprof/goroutine?debug=2' > g2.txt
然后用 diff g1.txt g2.txt 找持续增长的 goroutine 栈。典型泄漏模式:
- HTTP handler 里启了 goroutine 但没做超时或 context 取消
- channel 写入无缓冲且无人读,导致 sender 永久阻塞
- timer.AfterFunc 启动后未清理,底层 goroutine 不退出
pprof 本身不杀 goroutine,它只是告诉你“现在有多少、在哪卡住”。修复还得靠代码逻辑补全 cancel、加 buffer、用 select + default 防死锁。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











