notexOPENOverview
Notex/Languages/Tuning the Garbage Collector
04.17LESSON 17 OF 20 · 4 MIN READ

Tuning the Garbage Collector

Always free to read

The garbage collector doesn’t immediately reclaim memory as soon as it is no longer referenced. Doing so would seriously impact performance. Instead, it lets the garbage pile up for a bit. The heap almost always contains both live data and memory that’s no longer needed.

The Go runtime provides a couple of settings you can use to control the heap’s size. The first is the GOGC environment variable. The garbage collector looks at the heap size at the end of a garbage-collection cycle and uses the formula CURRENT_HEAP_SIZE + CURRENT_HEAP_SIZE*GOGC/100 to calculate the heap size that will trigger the next garbage-collection cycle.

Note

The GOGC heap-size calculation is a little more complicated than I just described. It accounts not just for the heap size, but also for the sizes of all goroutines’ stacks and the memory set aside to hold package-level variables. Most of the time, the heap is far bigger than these other memory areas, but in some situations their sizes do have an effect.

By default, GOGC is set to 100, which means that the heap size that triggers the next collection will be roughly double the heap size at the end of the current collection. Setting GOGC to a smaller value will decrease the target heap size, and setting it to a larger value will increase it. As a rough estimate, doubling the value of GOGC will halve the amount of CPU time spent on garbage collection.

Setting GOGC to off disables garbage collection. This will make your programs run faster. However, turning off garbage collection on a long-running process will potentially use all available memory on your computer, which is not usually considered optimal behavior.

The second garbage-collection setting caps the total amount of memory your Go program is allowed to use. Java developers are likely familiar with the -Xmx JVM argument; GOMEMLIMIT is similar. By default, it is disabled. (Well, technically, it is set to math.MaxInt64, but it’s unlikely that your computer has that much memory.) The value for GOMEMLIMIT is specified in bytes, but you can use the optional suffixes for bytes (B), kibibyes (KiB), mebibytes (MiB), gibibytes (GiB), and tebibytes (TiB). For example, GOMEMLIMIT=3GiB sets the memory limit to 3 GiB (which is equal to 3,221,225,472 bytes).

Note

If you haven’t seen these suffixes before, they are the official power-of-two analogues of the more commonly used power-of-ten units: kilobytes (KB), megabytes (MB), gigabytes (GB), and terabytes (TB). KiB is equal to 210, MiB is equal to 220, and so on. It is technically correct to use KiB, MiB, and friends when dealing with computers.

It might seem counterintuitive that limiting the maximum amount of memory could improve a program’s performance, but there are good reasons this flag was added. The primary reason is that computers (or virtual machines or containers) don’t have infinite RAM. If a sudden, temporary spike in memory usage occurs, relying on GOGC alone might result in the maximum heap size exceeding the amount of available memory. This can cause memory to swap to disk, which is very slow and might crash your program, depending on your operating system and its settings. Specifying a memory limit prevents the heap from growing beyond the computer’s resources.

GOMEMLIMIT is a soft limit that can be exceeded in certain circumstances. It’s common in garbage-collected systems that the collector can’t free up enough memory to get within the memory limit, or the garbage-collection cycles are rapidly triggered because a program repeatedly hits the limit. Called thrashing, this results in a program that does nothing other than run the garbage collector. If the Go runtime detects that thrashing is starting to happen, it will end the current garbage-collection cycle and exceed the limit. You should set GOMEMLIMIT below the maximum amount of available memory so you have spare capacity.

If you specify a value for GOMEMLIMIT, you could set GOGC to off and not run out of memory, but this may not produce the desired performance effect. You’re likely to find yourself trading frequent short pauses for infrequent longer pauses. If you are running a web service, this produces inconsistent response times—​one of the behaviors Go’s garbage collection was designed to avoid.

The best option to ensure that garbage collection happens at a reasonable pace and that the maximum is respected is to use these two environment variables together. You can learn more about how to use GOGC and GOMEMLIMIT by reading “A Guide to the Go Garbage Collector” from Go’s development team.

The Go standard library provides a way to peek into a running program’s memory usage: The ReadMemStats function in the runtime package populates a pointer to an instance of runtime.MemStats with the current values for many memory statistics, including the size of the heap (HeapAlloc), the number of times memory has been allocated from the heap (Mallocs), and the number of times memory has been freed from the heap (Frees). I’ll discuss other ways to gather information on a running program’s memory usage in the related discussion.

Progress is saved on this device.
KEEP EXPLORING

One note leads to another.

Back to the library →
⌕
Search across the entire library ⌘ K