Golang <-time.After() is not garbage collected before expiry

Recently I was investigating a memory leak problem in a Go application that boiled down to me not reading the documentation properly. Here’s a piece of code that caused memory consumption of multiple Gbs:

Below is the memory metrics graph from the app:

Image for post
Image for post

On the left side one can see the memory consumption before the fix, and on the right — after. The profiler showed that the <-time.After was the reason for the memory leak. I was really surprised until I read the doc which says:

The underlying Timer is not recovered by the garbage collector until the timer fires.

So the 9Gb of RAM that was periodically GCed suddenly made sense. We have 60K messages per second in the channel that would be about 18 million timers allocated at every given moment plus some indeterminate number waiting to be GCed.

Trivial refactoring helped to reduce memory consumption by a factor of 20.


Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store