time.After(d) каждый раз создает новый *time.Timer, который не может быть остановлен (нет доступа к Stop()). Таймер живет в памяти до истечения задержки.
// Утечка: каждая итерация создает новый таймер
for {
select {
case msg := <-ch:
process(msg)
case <-time.After(5 * time.Second): // новый Timer каждый раз!
fmt.Println("timeout")
}
}
// Правильно: один Timer, сбрасываемый через Reset
timer := time.NewTimer(5 * time.Second)
defer timer.Stop()
for {
select {
case msg := <-ch:
if !timer.Stop() {
<-timer.C
}
timer.Reset(5 * time.Second)
process(msg)
case <-timer.C:
fmt.Println("timeout")
timer.Reset(5 * time.Second)
}
}
При получении 1000 сообщений в секунду и таймауте 5 сек в памяти будет ~5000 незавершенных таймеров. Для горячих путей всегда используйте time.NewTimer + Reset.