skip to content

What does the GOGC environment variable control in a Go program, and what does its default of 100 mean?

level: juniorimportance: must knowfreq 55%

answer

  1. a percentage, not a byte count
  2. measured against what survived the last cycle
  3. 100 means grow by 100 percent
  4. double the live set, then collect
  5. read from the environment at start-up

basics

~20 s

GOGC sets how much the heap may grow between garbage collections, as a percentage of the live data kept after the last one. The default, 100, lets the heap roughly double before the next collection starts.

solid answer

~40 s

GOGC is a growth percentage, not a size. The runtime aims to start the next collection when the heap has grown by GOGC percent beyond the live data that survived the previous cycle, so GOGC=100 means "let the heap roughly double", GOGC=50 means "let it grow by half", and GOGC=400 means "let it grow to five times the live set". It is read from the environment when the process starts, and `GOGC=off` disables automatic collection entirely. Because it is a ratio, it puts no absolute cap on memory: if the live set doubles, the peak heap doubles with it at the same GOGC. Raising it buys fewer collections at the cost of a larger resident heap; lowering it does the reverse.

go deeper

for a junior

Be ready to state that GOGC is a percentage of the live heap, that the default is 100 meaning "let the heap roughly double", and that higher uses more memory and less CPU while lower does the opposite.

for a middle

Explain the arithmetic out loud with a concrete live-set number, and be able to say why the same GOGC gives a bigger peak heap when the live set grows. Know that the variable is read only at start-up.

for a senior

An interviewer expects you to reject "GOGC caps memory" immediately and to connect the value to a real workload shape — how a spiky service's peak heap moves with it, and what you would measure before changing it.

for a principal

Own the framing that GOGC is a conversion rate between memory and CPU, and that the right value is a budget decision made with numbers, not a default copied from a blog post.

## The one knob everyone meets first `GOGC` is the Go runtime's primary garbage-collection tuning knob. It is read from the environment once, when the process starts, and it holds a single integer: **a percentage describing how much the heap is allowed to grow before the next collection cycle begins.** ### The percentage is relative, not absolute After a collection finishes, the runtime knows how much data is still reachable — the **live set**. `GOGC` says how much *additional* memory may be allocated on top of that before the collector starts again: ``` next collection target ~= live set * (1 + GOGC/100) ``` With a 200 MB live set: - `GOGC=100` (default) — collect at roughly 400 MB (grow by 100%, i.e. double). - `GOGC=50` — collect at roughly 300 MB (grow by 50%). - `GOGC=400` — collect at roughly 1 GB (grow to five times the live set). - `GOGC=off` — never collect automatically at all. (In modern Go the target also accounts for goroutine stacks and globals, but the useful mental model is "live heap times one plus GOGC over one hundred".) ### What follows from it being a ratio The most common misunderstanding is treating `GOGC` as a memory limit. It is not: - **It sets no ceiling.** If your live set grows from 200 MB to 2 GB because you now cache more, the same `GOGC=100` will let the heap reach about 4 GB. The knob controls headroom, never the live data itself. - **It scales with load shape.** A service whose live set balloons during a spike gets a proportionally bigger peak heap during that spike. - **It is not a pause-time goal.** Go's collector is a concurrent, non-generational mark-sweep collector; stop-the-world phases are short and are not what `GOGC` tunes. `GOGC` decides *how often* cycles run and *how much garbage* is allowed to pile up between them. - **It is not a generation size.** Go has no young/old generations, so there is nothing analogous to sizing a nursery. ### Direction of the tradeoff A higher `GOGC` means more allocation is permitted between cycles, so cycles run less often and the collector consumes less CPU — while the process holds more memory. A lower `GOGC` means the opposite: a tighter heap, and a collector that runs far more often and takes a bigger share of CPU. That single sentence is the whole reason the knob exists: **it converts memory into CPU, in both directions.** ### GOGC=off `GOGC=off` disables the automatic trigger. The heap then only grows: every allocation adds to it and nothing is ever reclaimed unless the program explicitly calls `runtime.GC()`. It is defensible for a short-lived process that allocates a bounded amount and exits — a one-shot CLI, a compiler-like batch step — and it is a hazard for anything long-lived, because the process will keep growing until the operating system stops it. ### Changing it The environment variable is consulted at start-up, so exporting a new value or calling `os.Setenv` later has no effect on a running process. The runtime equivalent is `runtime/debug.SetGCPercent`, which takes the same percentage and applies it immediately. ### How to talk about it in an interview Say the number is a **percentage of the live set**, give one worked arithmetic example, name the default (100), and state the tradeoff direction. Then be explicit that it is not a memory cap — that distinction is what separates a candidate who has read the variable's name from one who has tuned a service with it.

  • Does GOGC put an upper bound on how much memory a Go process can use?
    No. It is a ratio applied to the live set, so it bounds headroom, not total memory. If the live set grows, the peak heap grows in proportion at the same GOGC. Capping absolute memory needs a different mechanism entirely; lowering GOGC only squeezes the garbage headroom and does nothing about the data that is genuinely still reachable.
  • What does GOGC=off actually do, and when is it defensible?
    It disables the automatic collection trigger, so the heap only grows; nothing is reclaimed unless the program calls runtime.GC() itself. It is reasonable for a short-lived process with a bounded allocation total — a one-shot CLI or batch step that exits quickly — and reckless for a long-running server, which will simply keep growing until the operating system kills it.
  • If a service's live set doubles overnight, what happens to its peak heap at an unchanged GOGC=100?
    It roughly doubles as well. The target is computed from the live set each cycle, so twice as much reachable data means twice as much allowed headroom on top of it. This is why a cache that quietly grows can double a service's memory footprint without anyone changing a single tuning value.

It is a restocking rule, not a warehouse size: "let the shelves fill to twice what is actually being used before we do a clear-out." If genuine stock doubles, the warehouse you need doubles too — the rule never caps the building.

saying these in an interview costs you the question

  • Calls GOGC a memory limit or a maximum heap size
  • Thinks GOGC is measured in megabytes rather than percent
  • Says GOGC=0 disables the collector (it does not; a negative value does)
  • Describes GOGC as a pause-time target
  • Assumes exporting GOGC changes a process that is already running
  • Talks about young and old generations, which Go's collector does not have