🔴 Сложный · 3 очк. Стандартная библиотека
Почему time.After может вызвать утечку памяти в цикле с select?
A time.After не утекает
B Каждый вызов создает новый Timer, который не освобождается до срабатывания; в цикле накапливаются тысячи незавершенных таймеров
C Утечка только на Windows
D Утечка только при таймауте больше минуты
Объяснение вопроса

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.

🧠Квиз 🏆Лидеры 🎯Собесед. 📖Вопросы 📚База зн.