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: горутина - дешёвый ресурс, но не бесплатный.

И если сервис создаёт их постоянно, полезно уметь проверить не только сколько их стало, но и почему они никогда не заканчиваются.