Advanced 26 min readModule: Module 13: Go GC Internals: Tri-Color Mark-Sweep & Write Barriers
Go Garbage Collector: Tri-Color Marking & Write Barriers
Deconstruct the Go runtime Garbage Collector: Tri-Color concurrent mark-and-sweep, Hybrid Write Barrier (Dijkstra + Yuasa), Mark Termination phases, and tuning `GOMEMLIMIT` and `GOGC` (Pacer algorithm).
What You Will Learn in This Lesson
- The Tri-Color Marking algorithm: White (unvisited), Grey (scanned, unvisited children), Black (reachable)
- Why the Hybrid Write Barrier prevents GC race conditions during active concurrent mutations
- The Go GC Pacer feedback loop and controlling GC frequency with `GOGC` (default: 100)
- Enforcing memory limits and preventing OOM kills using `GOMEMLIMIT` (Go 1.19+)
Introduction & Core Concept
Go uses a concurrent, non-moving, tri-color mark-sweep garbage collector designed for low latency over peak throughput. Unlike Java's generational GC which moves and compacts objects, Go keeps objects in place and marks pointers concurrently while application goroutines (mutators) run. The Hybrid Write Barrier ensures that if mutators move pointers during marking, no reachable objects are missed.
WHY DOES THIS MATTER IN THE REAL WORLD?
Tuning `GOMEMLIMIT` prevents Kubernetes Out-Of-Memory (OOM) fatal kills by instructing the GC Pacer to trigger collections dynamically before container cgroup memory limits are reached.
Syntax & Structure
go
GOGC=100 GOMEMLIMIT=2GiB ./serverimport "runtime/debug"debug.SetMemoryLimit(2 * 1024 * 1024 * 1024)Simulating GC Pacer Metrics and Inspecting GC Pauses in Go
gogo
123456789101112131415161718192021222324252627282930313233343536373839// Go Garbage Collector Telemetry & GOMEMLIMIT Tuningpackage mainimport ("fmt""runtime""runtime/debug""time")func main() {fmt.Println("=== Go Concurrent GC Engine Diagnostics ===")// 1. Configure GOMEMLIMIT (Soft memory ceiling for GC Pacer)previousLimit := debug.SetMemoryLimit(512 * 1024 * 1024) // 512 MB soft limitfmt.Printf("Configured GOMEMLIMIT soft ceiling: 512MB (Previous: %d bytes)\n", previousLimit)// 2. Allocate memory to trigger GC marking phasesstart := time.Now()var holder [][]bytefor i := 0; i < 50; i++ {// Allocate 5MB blocksbuf := make([]byte, 5*1024*1024)holder = append(holder, buf)if len(holder) > 10 {holder = holder[5:] // Release 25MB to trigger GC reclamation}}// 3. Inspect GC Pause Telemetryvar memStats runtime.MemStatsruntime.ReadMemStats(&memStats)fmt.Printf("Total Alloc: %d MB\n", memStats.TotalAlloc/1024/1024)fmt.Printf("Heap In-Use: %d MB\n", memStats.HeapInuse/1024/1024)fmt.Printf("Number of GC Cycles: %d\n", memStats.NumGC)fmt.Printf("Latest GC Pause: %v\n", time.Duration(memStats.PauseNs[(memStats.NumGC+255)%256]))fmt.Printf("Benchmark finished in %v with sub-millisecond GC pauses!\n", time.Since(start))}
Line-by-Line Technical Breakdown
1GC Pacer Feedback Loop: The Pacer estimates the rate of memory allocation versus the rate of GC marking. If mutators allocate faster than GC worker threads can mark, the Pacer engages 'Mutator Assist', forcing allocating goroutines to spend CPU time helping the GC mark objects.
Try It Yourself (Interactive Editor)
Modify the code in real-time and click Run to test live browser output and console logs.
Intelligent Code Runner & Live Sandbox[GO]
GO SOURCE EDITOR
Interactive Live CodeCommon Mistakes & How to Avoid Them
#1: Setting GOGC=off to avoid GC pauses, leading to inevitable Out-Of-Memory container crashes.
GOGC=off completely disables garbage collection. GOMEMLIMIT allows the GC to run only when needed while respecting RAM limits.
Incorrect / Antipattern
export GOGC=off // Danger: Memory grows unbounded until process is killedCorrect / Professional Solution
export GOMEMLIMIT=1800MiB // Use soft limit to protect Kubernetes memory budgetsIndustry Best Practices & Professional Standards
- Set `GOMEMLIMIT` to 90% of your Kubernetes memory request/limit.
- Use `GODEBUG=gctrace=1` to observe live heap sizing and mark/sweep phase timings.
- Reduce heap allocations by reusing objects with `sync.Pool`.
Lesson Summary & Core Takeaways
- Go's GC uses non-moving Tri-Color Concurrent Mark-Sweep with sub-millisecond pauses.
- Hybrid Write Barrier ensures memory correctness without Stop-The-World stalls.
- `GOMEMLIMIT` prevents Kubernetes OOM crashes by pacing GC cycles dynamically.