Go

What does GOGC control, exactly? What happens with GOGC=off, 50 or 200?

Question 340MediumGo 1.22 to 1.25

GOGC sets the heap growth target relative to the live data left after the last collection. Since Go 1.18 the formula also counts GC roots:

heapGoal = liveHeap + (liveHeap + stacks + globals) * GOGC/100

With the default GOGC=100 and 100 MB live, the next cycle starts at roughly 200 MB total heap. The pacer starts marking before the goal is reached, so marking finishes right about at the goal.

  • GOGC=50: collects twice as often and uses less memory, at the cost of more GC CPU.
  • GOGC=200: collects about half as often and uses more memory, which means better throughput.
  • GOGC=off: never collects unless a memory limit is set. Useful for short CLI tools, or together with GOMEMLIMIT.
import "runtime/debug"

func init() {
    old := debug.SetGCPercent(200) // same as GOGC=200; returns previous value
    _ = old
}

Key insight: GC CPU cost scales with how often the collector runs multiplied by live heap size. Garbage itself costs nothing to collect, since sweeping is cheap. So doubling GOGC roughly halves GC CPU. That is the classic trade between memory and CPU.

Gotcha: with a tiny live heap, a GOGC-only setup triggers GC constantly, because the minimum heap goal is only 4 MB. This is the "Twitch ballast" problem that GOMEMLIMIT now solves.

More on Memory, GC & Runtime Internals

All 38 Memory, GC & Runtime Internals questions