Что такое утечка горутин и как её избежать?
- Почему растёт число горутин в сервисе?
Горутина, навсегда заблокированная на канале, мьютексе или вводе-выводе, никогда не завершится и держит стек и всё, на что ссылается. Типичные причины: отправка в канал, который никто не читает (вызывающий ушёл по таймауту), чтение из канала, который никто не закроет, сетевой вызов без таймаута.
- У каждой горутины должен быть понятный способ завершиться
- Отмена через context и select с ctx.Done()
- Буфер на 1 для результата позволяет отправителю завершиться, даже если ответ не нужен
А ещё Найти: runtime.NumGoroutine, pprof goroutine-профиль, goleak в тестах
Подробно
Почему это серьёзно. Сборщик мусора не освобождает заблокированные горутины — с точки зрения рантайма они живы. В долгоживущем сервисе их число растёт с каждым запросом, а с ними память и открытые соединения.
Правила:
- запуская горутину, знать, когда и как она завершится;
- передавать
contextи проверятьctx.Done()в циклах и select; - у внешних вызовов — таймауты (
http.Client{Timeout},context.WithTimeout); - закрывать каналы, по которым читают через range;
- результат «может быть никому не нужен» — канал с буфером 1.
Диагностика: метрика go_goroutines, /debug/pprof/goroutine?debug=1 показывает стеки — тысячи одинаковых стеков указывают на место утечки; go.uber.org/goleak проверяет в тестах, что горутин не осталось.
Пример
// утечка: при таймауте горутина навсегда висит на отправке
func fetch(ctx context.Context) (string, error) {
ch := make(chan string)
go func() { ch <- slowCall() }()
select {
case r := <-ch:
return r, nil
case <-ctx.Done():
return "", ctx.Err()
}
}
// исправление: make(chan string, 1) — отправка не заблокируетсяЧто хотят услышать
- Что такое утечка и типичные причины.
- Как предотвращать.
- Как обнаружить.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Горутины завершаются сами при выходе из функции, которая их запустила, и GC их убирает
- ✗Сборщик мусора удаляет заблокированные горутины
- ✗Утечка горутин не занимает память
- ✓Горутина, навсегда заблокированная на канале; нужна отмена через context
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.