编程 Go 1.27 的 goroutineleak profile 转正:用 GC 可达性找永久阻塞的 goroutine

2026-11-15 21:03:30

Go 1.27 的 goroutineleak profile 转正:用 GC 可达性找永久阻塞的 goroutine

Go 1.27 里 goroutineleak profile 从实验特性转为正式可用(Go 1.26 中是实验)。这个 profile 报告泄漏的 goroutine,在 runtime/pprof 包中提供,同时对应 net/http/pprof 的端点 /debug/pprof/goroutineleak。

什么算 leaked goroutine

定义很窄:阻塞在某个并发原语上(channel、sync.Mutex、sync.Cond 等),并且不可能被解除阻塞的 goroutine。仅仅“卡住很久”不算,必须是永远醒不过来的那种。

检测原理:靠 GC 的可达性

运行时用垃圾回收器来判断泄漏。若 goroutine G 阻塞在并发原语 P 上,而 P 从任何可运行的 goroutine、或从那些可能被它们解除阻塞的 goroutine 出发都不可达,那么 P 就无法被解除阻塞,G 也就永远无法唤醒。

无法在所有情况下检测出永久阻塞的 goroutine,但这一思路能覆盖相当大一类泄漏。

盲区

因为检测建立在可达性之上,以下情况可能漏检:阻塞的并发原语通过全局变量可达,或通过某个可运行 goroutine 的局部变量可达。换句话说,“还有人持有它”的原语不会被判定为永久阻塞。

采集

runtime/pprof 里按 profile 名 goroutineleak 取;起了 net/http/pprof 的服务可以直接拉:

go tool pprof http://host:6060/debug/pprof/goroutineleak

其他变更

  • goroutineleakprofile 这个 GOEXPERIMENT 已删除,不需要再显式开启。
  • Go 1.27 起,go 指令配置为 1.27 或更高版本的模块,其 traceback 头行会带上 runtime/pprof 的 goroutine labels;可用 tracebacklabels=0 GODEBUG 关闭。

排查工作流

  1. 先看 goroutine 数量的增长趋势,确认是持续上涨而非业务峰值的正常波动。
  2. 取 goroutineleak profile,而不是普通的 goroutine profile —— 后者会把正常运行中的阻塞也全部列出来。
  3. 拿 profile 里的阻塞点回业务代码对照:无人接收的 channel、没有释放路径的锁、sync.Cond 等不到的信号,通常是这几类。

这项工作由 Uber 的 Vlad Saioc 贡献。Go 1.27 于 2026 年 8 月发布。

复制全文 生成海报 Go 性能诊断 pprof

推荐文章

程序员茄子在线接单