线上服务突然慢了?我用 pprof 三分钟定位到根因 线上服务突然慢了我用 pprof 三分钟定位到根因前言线上服务突然变慢翻日志看不出问题重启也治标不治本。最怕这种上不去的故障。后来我学会了 pprof再遇到这种问题三分钟就定位到了。今天就聊聊怎么用 pprof 做内存和 CPU 分析。一、底层原理1.1 pprof 是怎么抓数据的pprof 通过采样来收集数据graph TD A[应用程序] -- B[CPU采样] A -- C[堆采样] A -- D[协程快照] B -- E[每10ms中断一次] E -- F[记录当前栈] F -- G[生成火焰图] C -- H[分配记录] H -- I[内存分析] D -- J[协程状态] J -- K[死锁检测]关键点CPU 采样是周期性中断损耗小堆采样记录每次分配协程快照能看到当前所有 goroutine分析结果可以导出成可视化图表1.2 pprof 数据类型对比类型用途采样方式CPU看 CPU 热点定时中断Heap看内存分配分配记录Goroutine看协程状态快照Block看锁竞争等待事件Mutex看互斥锁锁等待二、快速上手引入 pprofpackage main import ( fmt net/http _ net/http/pprof time ) func busyLoop() { for i : 0; i 1000000000; i { _ i * i } } func main() { go func() { fmt.Println(http.ListenAndServe(:6060, nil)) }() for i : 0; i 10; i { go busyLoop() } time.Sleep(30 * time.Second) }运行后浏览器打开http://localhost:6060/debug/pprof/就能看到数据。三、核心 API / 深水区3.1 pprof 常用命令速查命令说明go tool pprof http://localhost:6060/debug/pprof/heap内存分析go tool pprof http://localhost:6060/debug/pprof/profileCPU 分析go tool pprof http://localhost:6060/debug/pprof/goroutine协程分析top看占用最多的函数list 函数名看具体代码web打开可视化界面3.2 内存逃逸分析// 看内存分配热点 // go tool pprof http://localhost:6060/debug/pprof/allocs func createObjects() { for i : 0; i 100000; i { obj : SomeStruct{ // 逃逸了吗 data: make([]byte, 1024), } _ obj } }3.3 协程泄漏排查// http://localhost:6060/debug/pprof/goroutine?debug2 // 看所有协程的栈信息 func findLeak() { ch : make(chan struct{}) go func() { // 这个协程永远不退出 -ch }() }四、实战演练定位一个真实的内存泄漏package main import ( fmt net/http _ net/http/pprof time ) var leakMap make(map[int][]byte) func leakSimulator() { for i : 0; i 100000; i { // 内存泄漏 leakMap[i] make([]byte, 1024) } } func main() { go leakSimulator() go func() { fmt.Println(http.ListenAndServe(:6060, nil)) }() time.Sleep(time.Hour) }排查步骤go tool pprof http://localhost:6060/debug/pprof/heap输入 top 看排名输入 list leakSimulator 看代码发现 leakMap 一直在增长五、避坑指南与最佳实践 **技巧pprof 对性能有轻微影响生产环境不要一直开用的时候再开。⚠️ **警告Heap 分析要对比两次单次看意义不大要看增长趋势。✅ **推荐定时抓取保存写个定时任务定期抓 pprof 数据。六、综合实战演示生产级 pprof 集成package main import ( fmt log net/http _ net/http/pprof os runtime runtime/pprof time ) type Profiler struct { cpuFile *os.File memFile *os.File } func NewProfiler() *Profiler { return Profiler{} } func (p *Profiler) StartCPU() error { f, err : os.Create(cpu.pprof) if err ! nil { return err } p.cpuFile f pprof.StartCPUProfile(f) return nil } func (p *Profiler) StopCPU() { pprof.StopCPUProfile() if p.cpuFile ! nil { p.cpuFile.Close() } } func (p *Profiler) WriteHeap() error { f, err : os.Create(heap.pprof) if err ! nil { return err } defer f.Close() return pprof.WriteHeapProfile(f) } func (p *Profiler) WriteGoroutine() error { f, err : os.Create(goroutine.pprof) if err ! nil { return err } defer f.Close() runtime.GC() return pprof.Lookup(goroutine).WriteTo(f, 0) } func main() { profiler : NewProfiler() // 启动 CPU 分析 if err : profiler.StartCPU(); err ! nil { log.Fatal(err) } // 模拟业务逻辑 go func() { for i : 0; i 60; i { time.Sleep(time.Second) // 定期写内存 profiler.WriteHeap() } }() go func() { fmt.Println(http.ListenAndServe(:6060, nil)) }() // 跑 60 秒 time.Sleep(60 * time.Second) profiler.StopCPU() fmt.Println(pprof 数据已保存) }分析命令# CPU 分析 go tool pprof cpu.pprof # 内存分析 go tool pprof heap.pprof # 生成火焰图 go tool pprof -http:8080 cpu.pprof七、总结pprof 是排查性能问题的利器代码里引入 pprof用 go tool pprof 分析数据看 top、看火焰图定位到具体代码行有了 pprof性能问题不再是玄学。