go 1.27: теперь можно искать утечки горутин
Обычно, когда говорят про утечки памяти в Go, вспоминают: большие slices; maps; ссылки на ненужные объекты. Но есть ещё один неприятный вариант - утечки горутин. Например:
func worker() { ch := make(chan int) go func() { value := <-ch fmt.Println(value) }() }
Если никто никогда не отправит значение в ch, goroutine останется заблокированной навсегда.
В реальном сервисе таких goroutine может постепенно накопиться тысячи. Что нового в Go 1.27?
В runtime/pprof появился отдельный профиль: goroutineleak
А для HTTP-сервера доступен endpoint:
/debug/pprof/goroutineleak
Он позволяет искать goroutine, которые заблокированы на concurrency primitives и уже не могут быть разблокированы.
Например:
goroutine ↓ channel / mutex / cond ↓ никто не может её разблокировать ↓ goroutine leak
Это уже не просто:
"у меня почему-то растёт количество goroutines"
А возможность посмотреть на проблему через profiling.
При этом Go не может обнаружить абсолютно все варианты утечек. Например, часть случаев с глобальными переменными остаётся за пределами этого механизма.
Для меня это одна из самых интересных небольших фич Go 1.27: горутина - дешёвый ресурс, но не бесплатный.
И если сервис создаёт их постоянно, полезно уметь проверить не только сколько их стало, но и почему они никогда не заканчиваются.