




pprof是Go性能分析核心工具,需导入"net/http/pprof"启用HTTP服务,通过/debug/pprof获取CPU、heap、goroutine等数据,用go tool pprof交互分析定位热点、内存泄漏与协程泄漏。
Go程序跑得慢,八成不是CPU卡住,而是GC在疯狂停顿——PauseTotalNs飙升、NumGC暴涨,goroutine调度直接卡死。别急着重写算法,先让程序自己“说话”。
新手最容易对着fmt.Sprintf一顿优化,结果profile一看它只占0.2%耗时,而json.Unmarshal吃掉65%。性能问题必须靠数据定位,不是靠直觉。
import _ "net/http/pprof",再起个goroutine监听localhost:6060
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30go tool pprof http://localhost:6060/debug/pprof/heap(重点看allocs_space)go tool pprof http://localhost:6060/debug/pprof/goroutine?debug=2
go tool compile -gcflags="-m":查清变量是否逃逸到堆,比如&v在for range里反复取地址,就必然逃逸HTTP handler里每次make([]byte, 4096),一秒钟上千请求就是上千次堆分配,GC很快顶不住。但Pool不是万能膏药,乱用反而污染数据或浪费内存。
[]byte、bytes.Buffer)*RequestCtx、*JWTToken)Put前务必清空字段,比如buf.Reset()、m = make(map[string]string),否则下次Get拿到的是脏数据make([]T, 0),明确长度就写make([]T, 0, N);map也一样,make(map[string]int, 100)比默认容量少一半扩容开销一个泄漏的goroutine不占CPU,但持续吃2KB栈内存、阻塞channel、拖慢GC扫描——运行一周后runtime.NumGoroutine()从300涨到30000,OOM只是时间问题。
context,上
ch
— timer未Stop(),或time.AfterFunc绑定闭包导致引用无法释放
— channel无缓冲且读端已退出,写端一直阻塞
go tool pprof http://localhost:6060/debug/pprof/goroutine?debug=2看堆栈,重点关注长期停留在select、chan send、timer的地方ctx.Done(),用select { case 做快速退出检查
真正卡住服务的,往往不是某行代码多花了10μs,而是sync.Pool忘了清空字段、for range里取了错误地址、或者HTTP client没配Timeout——这些细节不显眼,但会在高并发下指数级放大。优化不是改完就完,是每次上线后都盯一眼PauseTotalNs和goroutine数。