Friday 2 June 2017

Golang gotcha #5: launched timers cannot be garbage collected till stopped or fired

You may run into this gotcha if you run timers with long timeouts in a tight for select loop. It is idiomatic to use a timer in order to provide a timeout on a channel receive. It is common to use time.After for this, because time.After is very easy to use as it provides a '<-chan Time', equivalent to 'NewTimer(d).C', but there is no way to stop it. And as the godoc says:

The underlying Timer is not recovered by the garbage collector until the timer fires. If efficiency is a concern, use NewTimer instead and call Timer.Stop() if the timer is no longer needed.

This example demonstrates such a leak when using time.After:
timer_leak.go
https://play.golang.org/p/XLY-isFtnn

This example demonstrates that the timers are not garbage collected even after the function they are launched in returns, as some may expect:
timer_leak_func.go
https://play.golang.org/p/W3rjZ5ziFb

This example demonstrates that stopping the timers resolves the leak:
timer_no_leak.go
https://play.golang.org/p/5CThl1JbaS

This may seem like an unnecessary optimisation but in the right circumstances, a tight for loop with a long lived timer, these can really add up.

No comments:

Post a Comment