3.5Kпросмотров
19 декабря 2025 г.
statsScore: 3.8K
Утечки горутин в Go 1.24+ Вы конечно и так в курсе, но на всякий случай: Утечка происходит, если одна или несколько горутин навсегда заблокировались на канале (или другом примитиве синхронизации), но другие горутины и программа в целом при этом продолжают работать. Утрированный пример утечки: func work() chan int { ch := make(chan int) go func() { ch <- 42 ch <- 13 // (!) утечка }() return ch
} func main() { <-work() // ...
} Традиционно Go не очень-то помогал в поиске утечек. Обнаружить их можно было разве что пристально разглядывая профиль или трассировку с продакшена, а в тестах приходилось использовать сторонний пакет goleak от Убера. Сейчас это меняется. Сначала в Go 1.24 добавили пакет synctest, который прекрасно справляется с поиском утечек при тестировании. Об этом почему-то никто не говорит — наверно, потому что не проходили мой курс по многозадачности 😁 func Test(t testing.T) { synctest.Test(t, func(t testing.T) { <-work() synctest.Wait() })
} panic: main bubble goroutine has exited but blocked goroutines remain goroutine 37 [chan send (durable), synctest bubble 1]:
main.work.func1() leak_test.go:12 +0x3c
created by main.work in goroutine 36 leak_test.go:10 +0x6c Как видите, тест и ругнулся, и точно указал, где возникла утечка. А теперь в Go 1.26 подвезут новый pprof-профиль под названием goroutineleak — он надежно (без ложных срабатываний) обнаруживает утечки в продакшене (как вы понимаете, synctest-то в продакшене не запустишь). func main() { prof := pprof.Lookup("goroutineleak") defer func() { time.Sleep(50 * time.Millisecond) prof.WriteTo(os.Stdout, 2) }() <-work()
} goroutine 3 [chan send (leaked)]:
main.work.func1() leak.go:12 +0x3c
created by main.work in goroutine 1 leak.go:10 +0x74 Как видите, указал ровно на ту же утечку, что synctest. В общем, рекомендую оба инструмента. За подробностями велкам в блог: https://antonz.org/detecting-goroutine-leaks