Golang / Golang Internals and Memory Management Interview Questions
How does Go's garbage collector work? Explain the tri-color mark-and-sweep algorithm.
Go uses a concurrent, tri-color mark-and-sweep garbage collector. The key design goal is to minimize Stop-The-World (STW) pauses to sub-millisecond levels, even on large heaps, allowing Go programs to remain responsive under continuous allocation pressure.
| Color | Meaning |
|---|---|
| White | Not yet visited. At GC end, white objects are unreachable — will be freed. |
| Grey | Reachable from a root, but outgoing references not yet scanned. |
| Black | Fully scanned. All references from this object have been processed. |
Algorithm phases:
- STW start (~100 µs): pauses all goroutines briefly to take a consistent root snapshot and enable the write barrier.
- Concurrent mark: GC goroutines run alongside application goroutines, turning grey objects black by scanning their references. Application goroutines continue executing.
- Write barrier: while marking is concurrent, the program may create new pointers. The write barrier (Dijkstra/hybrid) intercepts pointer writes and shades the pointed-to object grey so it is not missed.
- Mark termination (STW) (~100 µs): a second brief pause to drain the grey queue and disable the write barrier.
- Concurrent sweep: white (unreachable) objects are swept back into free lists. This is concurrent — no STW needed.
// Trigger GC manually (rarely needed in production) import "runtime" runtime.GC() // triggers a full GC cycle // Read GC stats var stats runtime.MemStats runtime.ReadMemStats(&stats) fmt.Printf("NumGC: %d\n", stats.NumGC) fmt.Printf("PauseTotal: %v\n", time.Duration(stats.PauseTotalNs)) fmt.Printf("HeapAlloc: %d MB\n", stats.HeapAlloc/1024/1024) // GOGC env â controls GC frequency // GOGC=100 (default): GC triggers when heap grows 100% above last GC live set // GOGC=200: GC triggers at 200% â less frequent GC, more memory used // GOGC=off: disables GC (only for benchmarks) // GOMEMLIMIT (Go 1.19+) â hard memory limit // GOMEMLIMIT=500MiB triggers GC more aggressively if heap approaches 500 MB
The write barrier overhead (~5–10% CPU in allocation-heavy code) is the price paid for concurrent marking. In Go 1.22+, the runtime adaptively adjusts GC frequency using GOGC together with GOMEMLIMIT to balance latency and throughput automatically.
More Related questions...