Ответ
Утечка горутин — это ситуация, когда горутина остается заблокированной навсегда и никогда не завершается. Это приводит к утечке её стека и других ресурсов. Для обнаружения таких проблем используется встроенный в Go инструмент для профилирования — pprof
.
Шаг 1: Инструментирование кода
Добавьте в ваше приложение HTTP-сервер с эндпоинтами pprof
. Обычно это делается в main.go
.
import (
_ "net/http/pprof" // Анонимный импорт для регистрации обработчиков
"net/http"
"log"
)
func main() {
// ... ваш основной код ...
// Запускаем pprof сервер в отдельной горутине
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
// ... ваш основной код ...
}
Шаг 2: Анализ утечки горутин
- Запустите приложение.
- Когда вы подозреваете, что произошла утечка, выполните в терминале команду:
go tool pprof http://localhost:6060/debug/pprof/goroutine
- В интерактивной консоли
pprof
введите командуtop
. Она покажет группы горутин с одинаковым стеком вызовов. Если вы видите большое и постоянно растущее число горутин, заблокированных в одном и том же месте, — это главный кандидат на утечку. - Команда
traces
покажет полные стеки вызовов для всех горутин, что поможет точно определить место блокировки.
Шаг 3: Анализ утечки памяти
Утекающие горутины часто удерживают память. Для анализа памяти используется профиль heap
.
go tool pprof http://localhost:6060/debug/pprof/heap
С помощью команд top
, list <имя_функции>
и web
можно найти объекты, которые занимают больше всего памяти, и код, который их создает.
Типичные причины утечек горутин:
- Незакрытые каналы: Горутина ждет данных из канала, в который больше никто никогда не запишет.
- Заблокированные каналы: Отправка в канал, из которого никто не читает (если канал небуферизованный или переполнен).
- Бесконечные циклы: Циклы без условия выхода или ожидания отмены.
- Отсутствие обработки отмены в
select
: Горутина блокируется на канале, игнорируя при этомctx.Done()
.