Member-only story

How Go 1.23 eliminates Timer and Ticker memory leaks?

Peter Gillich
Dev Genius
Published in
4 min readFeb 9, 2025

Before Go 1.23, the developers had to write a few lines at the defer statement, in order to make sure, possible memory leaks were avoided.

If you cannot see the whole article, click here.

Image from Go: Timers’ Life Cycle

The issue

Before Go 1.23, the GC could not free the allocated memory of time.Timer and time.Ticker, until the time.Timer (used by time.Ticker) instance has not Stopped and drained.

It’s not mentioned at the documentation of time.NewTimer, see time.NewTimer@1.22, but mentioned only at time.Stop, see time.Stop@1.22:

To ensure the channel is empty after a call to Stop, check the return value and drain the channel. For example, assuming the program has not received from t.C already:

if !t.Stop() {
<-t.C
}

Practically, the channel close (called by time.Stop) and channel draining should always be added at defer statement, after the time.NewTimer or time.NewTicker, for example:

timer := time.NewTimer(100 * time.Millisecond)
defer func() {
if !timer.Stop() {
<-timer.C
}
}()

This pattern must be used manually, which is easy to forget.

Behind this behavior, there is a Golang design concept: a channel can be garbage collected, if it’s…

--

--

No responses yet

Write a response