The memory leak occurs because time.After creates a timer that is not cancelled when the loop exits or the channel is not read, causing the timer to remain in memory until it fires. To fix this, use time.NewTimer and explicitly call Stop() on the timer when it is no longer needed, or use time.AfterFunc with a cleanup mechanism. Here is the corrected pattern:
for {
select {
case <-done:
return
default:
timer := time.NewTimer(1 * time.Second)
select {
case <-timer.C:
// Do work
case <-done:
timer.Stop()
return
}
}
}
Alternatively, if you must use time.After, ensure the loop has a way to exit and the timer is not created in a tight loop without cancellation.