GC CPU limiter
A safeguard added in Go 1.19 that caps the CPU time the collector can take, around 50 percent, when the memory limit is reached.
A safeguard added in Go 1.19 that caps the CPU time the collector can take, around 50 percent, when the memory limit is reached.
With a memory limit close to the live heap, the collector could run continuously and starve the program, a death spiral. The limiter tracks the fraction of CPU used by GC and assists in a sliding window and, when it exceeds 50 percent, lets the program allocate over the limit instead.
The memory limit is therefore soft: the program may exceed GOMEMLIMIT temporarily rather than stop making progress. If gctrace shows back-to-back cycles with the heap near the limit, the live heap is too large for the limit: raise the limit or reduce memory use.
Official documentation: A Guide to the Go Garbage Collector
GOGC
The main Go GC tuning knob: the percentage of the live heap that may be allocated before the next cycle starts. The default is 100.
With GOGC=100, the heap goal is twice the live heap (plus stacks and globals, since Go 1.18): a program with 100 MiB of live heap starts a cycle at about 200 MiB. Doubling GOGC doubles the extra memory and roughly halves the CPU cost of GC, and the other way round. Set it with the GOGC environment variable or debug.SetGCPercent. GOGC=off disables the collector, which is only reasonable together with a memory limit.
In gctrace, compare the heap sizes (at start, at end, live) with the goal. A program with a small, stable live heap and plenty of spare memory can raise GOGC to spend less CPU on GC. A program in a container close to its memory limit should rather use GOMEMLIMIT.
Official documentation: A Guide to the Go Garbage Collector
GOMEMLIMIT
A soft limit on the total memory used by the Go runtime, available since Go 1.19. The collector works harder as usage approaches it.
The limit covers the whole runtime: heap, stacks and runtime structures, not memory returned to the OS. When the total approaches it, the collector runs more often than GOGC alone would require, trading CPU for memory. The limit is soft: if the live data really exceeds it, the program keeps running, and the GC CPU limiter prevents the collector from taking over the CPU.
A typical setup in a container is a limit 5 to 10 percent below the container memory, with GOGC unchanged or off. Set it with the GOMEMLIMIT environment variable (for example 900MiB) or debug.SetMemoryLimit. When the limit binds, cycles become frequent and the share of CPU spent in GC rises.
Official documentation: A Guide to the Go Garbage Collector
GC CPU limiter