Golang / Golang Internals and Memory Management Interview Questions
What are GOGC and GOMEMLIMIT and how do you use them to tune GC behavior?
Go's GC is controlled by two primary knobs: GOGC (the classic throughput knob) and GOMEMLIMIT (the memory ceiling introduced in Go 1.19).
| Variable | Default | Meaning |
|---|---|---|
| GOGC | 100 | GC triggers when live heap grows by GOGC% since last GC |
| GOMEMLIMIT | math.MaxInt64 (off) | Hard memory limit; GC runs more aggressively when heap approaches this |
// GOGC examples (set as environment variable or via runtime/debug) // GOGC=100 (default) â GC when heap is 2x last-collection live set // GOGC=200 â GC when heap is 3x â fewer GCs, more memory // GOGC=50 â GC when heap is 1.5x â more frequent, lower peak // GOGC=off â disable GC (benchmarks/short programs only) import "runtime/debug" // Set programmatically (returns old value) oldGOGC := debug.SetGCPercent(200) // increase to reduce GC frequency defer debug.SetGCPercent(oldGOGC) // GOMEMLIMIT â prevents OOM by forcing GC before memory is exhausted // GOMEMLIMIT=500MiB debug.SetMemoryLimit(500 * 1024 * 1024) // 500 MB hard limit // Best practice for containerized Go services: // Set GOMEMLIMIT to ~90% of container memory limit // This prevents OOM kills while allowing GC to breathe // Example: container limit 1 GiB â GOMEMLIMIT=900MiB // Runtime metrics (Go 1.16+) import "runtime/metrics" samples := []metrics.Sample{ {Name: "/gc/cycles/total:gc-cycles"}, {Name: "/memory/classes/heap/objects:bytes"}, } metrics.Read(samples) fmt.Println(samples[0].Value.Uint64()) // total GC cycles
The interaction between the two: if GOGC=100 would trigger GC at 2 GB but GOMEMLIMIT=1.5 GB, the runtime will trigger GC earlier to stay under the limit. This makes containerised deployments safer — previously, a spike in allocations could cause an OOM kill before GC had a chance to run.
More Related questions...