Skip to content

Instantly share code, notes, and snippets.

@rednafi
Last active June 18, 2026 20:35
Show Gist options
  • Select an option

  • Save rednafi/4f6fe8545580adfa8f6df2e5ed7b9a0e to your computer and use it in GitHub Desktop.

Select an option

Save rednafi/4f6fe8545580adfa8f6df2e5ed7b9a0e to your computer and use it in GitHub Desktop.
Go 1.27 goroutine leak profile (golang/go#74609): formats, HTTP, and a failing test. Run with GOEXPERIMENT=goroutineleakprofile
// Goroutine leak profile, accepted for Go 1.27 (golang/go#74609).
// Run: GOEXPERIMENT=goroutineleakprofile go run formats.go
package main
import (
"bytes"
"fmt"
"os"
"runtime"
"runtime/pprof"
)
func leakSend() {
ch := make(chan int)
go func() { ch <- 1 }() // nobody receives, the send blocks forever
}
func leakRange() {
ch := make(chan int)
go func() {
for range ch { // ch is never closed, the range never ends
}
}()
}
func main() {
leakSend()
leakRange()
runtime.Gosched() // let both goroutines reach their blocked state
p := pprof.Lookup("goroutineleak")
// Gotcha: Count() is 0 until a WriteTo runs the leak-detecting GC cycle.
fmt.Println("Count() before WriteTo:", p.Count())
var proto bytes.Buffer
p.WriteTo(&proto, 0) // debug=0: gzipped pprof protobuf for `go tool pprof`
fmt.Printf("debug=0: %d gzipped bytes\n", proto.Len())
fmt.Println("Count() after WriteTo:", p.Count())
fmt.Println("--- debug=1: leaked goroutines as text ---")
p.WriteTo(os.Stdout, 1)
fmt.Println("--- debug=2: full dump, leaked ones tagged (leaked) ---")
p.WriteTo(os.Stdout, 2)
}
// Fail a test on leaks the way uber-go/goleak does, but from the stdlib.
// Run: GOEXPERIMENT=goroutineleakprofile go test
package main
import (
"bytes"
"runtime"
"runtime/pprof"
"testing"
)
// verifyNone mirrors goleak.VerifyNone: fail the test on any leaked goroutine.
func verifyNone(t *testing.T) {
var b bytes.Buffer
p := pprof.Lookup("goroutineleak")
p.WriteTo(&b, 1) // WriteTo runs detection; Count() reads 0 without it
if p.Count() > 0 {
t.Fatalf("leaked goroutines:\n%s", b.String())
}
}
func TestRun(t *testing.T) {
defer verifyNone(t) // like defer goleak.VerifyNone(t)
ch := make(chan int)
go func() { ch <- 1 }() // the code under test leaks a goroutine
runtime.Gosched()
}
// Pull leaks from a running service over HTTP.
// Run: GOEXPERIMENT=goroutineleakprofile go run server.go
// Then: curl 'localhost:6060/debug/pprof/goroutineleak?debug=1'
package main
import (
"net/http"
_ "net/http/pprof" // registers /debug/pprof/goroutineleak
)
func main() {
ch := make(chan int)
go func() { ch <- 1 }() // leak
http.ListenAndServe("localhost:6060", nil)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment