thecodex.expert · The Codex Family of Knowledge
Go

Memory and Garbage Collection

Go decides at compile time whether a variable lives on the stack or the heap — not by where you declared it, but by whether its address ever escapes the function.

Go 1.26 Concurrent GC Last verified:
Canonical Definition

Go manages memory automatically with a concurrent, tri-color mark-and-sweep garbage collector, designed to run alongside your program with very short stop-the-world pauses rather than freezing execution for long collection cycles. Separately, the compiler performs escape analysis on every variable to decide whether it can be safely allocated on the function’s stack (fast, automatically freed on return) or must “escape” to the heap (managed by the garbage collector) because a reference to it outlives the function call.

Escape analysis: stack vs. heap

A value stays on the stack if the compiler can prove nothing outside the function can reference it after it returns; if a pointer to it is returned, stored in a global, or sent to a goroutine, it "escapes" to the heap.

Goescape.go
func onStack() int {
    x := 42          // never referenced outside; stays on the stack
    return x
}

func onHeap() *int {
    x := 42          // its address is returned, so it escapes to the heap
    return &x        // safe in Go (unlike C) — the GC keeps it alive
}

You can see these decisions directly with go build -gcflags="-m", which prints each escape-analysis decision the compiler made.

Why the collector is concurrent

Go's GC runs mark and sweep phases concurrently with your program's goroutines, using short stop-the-world pauses (typically well under a millisecond) only for phase transitions rather than pausing for the entire collection. This matters specifically because Go programs are often long-running network services, where a multi-second GC pause would show up as a visible latency spike to users.

Tuning with GOGC and GOMEMLIMIT

The GC's aggressiveness can be tuned with the GOGC environment variable (default 100, meaning "collect again once heap size doubles since the last collection") and, since Go 1.19, GOMEMLIMIT, which sets a soft memory cap the GC works to stay under — useful in containerized environments with a fixed memory limit.

Goterminal
$ GOGC=50 ./myserver          // collect more aggressively (smaller heap, more CPU)
$ GOMEMLIMIT=512MiB ./myserver // soft cap, useful inside a memory-limited container

Sources

1
The Go Authors. "A Guide to the Go Garbage Collector", go.dev/doc/gc-guide.