Go 1.27's goroutine leak profiler pinpoints production leaks with zero false positives

Goroutine Leak Profiles

Go 1.27's goroutine leak profiler pinpoints production leaks with zero false positives

Go 1.27 introduces a goroutine leak profiler that detects goroutines permanently blocked on channels or sync primitives in running programs, including production. Unlike goleak and synctest, which are limited to tests, it uses a modified garbage collector to trace liveness from unblocked goroutines, reporting only true leaks. The trade-off: it misses leaks blocked on I/O or global variables, and can be slower than the regular GC.

A goroutine is live if: 1. it is not blocked by a concurrency primitive, or 2. at least one concurrency primitive that blocks it is referenced by another live goroutine.
  1. sethammons

    General rule: never call a goroutine without understanding how it will close.

  2. deathanatos

    I'm coming predominately from other languages, so it took me a hot minute to figure out what the various bug were.

    • channels are by default "unbuffered", in that a send needs a waiting recv to actually do the send, and blocks until such. The addition of the buffer prevents the block & permits the goroutine to progress (and eventually exit, and thus, not leak) … so long as the buffer is sufficiently large enough.

    • channels do not, AFAICT, realize when the receiver is gone, and will block indefinitely even when there is no receiver. (It is the same "chan" object, I think, in both sender/receiver / there is no distinction. So, the single object is never GC'd.)

    • goroutines are not GC'd. (& the code doesn't/can't hold like, a reference or a handle to a goroutine / there is no "join" primitive.)

More from this day

2026-09-19