Go garbage collection

Go automatically frees heap memory when heap allocated memory does not have reference. We never call free or delete. Pause times are kept low.
Go routines live on heap in Go process memory layout
Garbage collector lies on Process's Text Area/Code Area section

Simple example (Linked List)

type Node struct {
    Value int
    Next  *Node
}
func main() {
    a := &Node{Value: 10}
    b := &Node{Value: 20}
    c := &Node{Value: 30}

    a.Next = b
    b.Next = c
}

Stack/root -> a -> b -> c
Suppose Later
a = nil

[Node A] ---> [Node B] ---> [Node C]

A, B, C becomes garbage and are collected by GC later

How GC works = Tri-color Marking(White, Grey, Black)

These are 3 buckets:

Bucket White Grey Black
Meaning Garbage Reachable, but work remains Reachable and fully scanned

root
 |
 v
[A] ---> [B] ---> [C]

time 0. White=A,B,C
time 1. Grey=A,  White=B,C              // A(Reachable, but work remains)
time 2. Black=A,  Grey=B,   White=C     // A(Reachable and fully scanned), B(Reachable, but work remains)
      

Why tri color scheme

Go doesn't want to stop the entire application while it scans the heap.
Go's GC is concurrent, ie it keeps marking while you keep on allocating heap. stop-the-world (STW) phases should be low

Go vs Java GC

Same core idea: both are tracing collectors — start from roots, follow references, reclaim what is unreachable. Neither requires you to free individual objects on the heap.

Go Java
Heap model Single Go heap (+ goroutine stacks on heap) Object heap + separate metaspace for class metadata
Generations Non-generational — no Eden / Old gen split Generational — Eden, survivor spaces, old generation (most collectors)
Concurrency Mark-and-sweep, mostly concurrent with app code Depends on collector (G1, ZGC, etc.); young GC often STW, modern collectors reduce pauses
Roots Goroutine stacks, globals, CPU registers Java thread stacks, static fields, JNI refs, etc.
What gets collected Heap objects; stack frames scanned for pointers Heap objects only (class data in metaspace, not GC’d like objects)
Allocation path Escape analysis — locals may stay on stack or move to heap Almost all objects allocated on heap (new)

Tuning GC

GOGC (default 100) — heap growth vs GC frequency. Higher = less frequent GC, more memory.
GODEBUG=gctrace=1 — print GC stats to stderr (useful when learning or debugging pauses).
Reduce unnecessary heap allocations (reuse buffers, avoid allocations in hot loops) — same advice as Java, but Go has no generational “Eden is cheap” assumption to the same degree.