Ответ
Утечка горутин — это ситуация, когда горутина остается заблокированной навсегда и никогда не завершается. Это приводит к утечке её стека и других ресурсов. Для обнаружения таких проблем используется встроенный в 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().