Minimizing GC Pressure

Strategies to reduce garbage collection overhead:

package main

import (
	"fmt"
	"runtime"
	"time"
)

// Struct with pointer fields - creates GC pressure
type HighPressure struct {
	name    *string
	value   *int
	enabled *bool
	data    *[]byte
}

// Struct with value fields - reduces GC pressure
type LowPressure struct {
	name    string
	value   int
	enabled bool
	data    []byte // Still contains a pointer, but fewer overall
}

func createHighPressureObjects(count int) []*HighPressure {
	result := make([]*HighPressure, count)
	for i := 0; i < count; i++ {
		name := fmt.Sprintf("object-%d", i)
		value := i
		enabled := i%2 == 0
		data := make([]byte, 100)
		
		result[i] = &HighPressure{
			name:    &name,
			value:   &value,
			enabled: &enabled,
			data:    &data,
		}
	}
	return result
}

func createLowPressureObjects(count int) []*LowPressure {
	result := make([]*LowPressure, count)
	for i := 0; i < count; i++ {
		result[i] = &LowPressure{
			name:    fmt.Sprintf("object-%d", i),
			value:   i,
			enabled: i%2 == 0,
			data:    make([]byte, 100),
		}
	}
	return result
}

func measureGCStats(label string, f func()) {
	// Clear previous garbage
	runtime.GC()
	
	// Get initial stats
	var statsBefore runtime.MemStats
	runtime.ReadMemStats(&statsBefore)
	
	startTime := time.Now()
	
	// Run the test function
	f()
	
	// Force final GC to get accurate measurements
	runtime.GC()
	
	duration := time.Since(startTime)
	
	// Get final stats
	var statsAfter runtime.MemStats
	runtime.ReadMemStats(&statsAfter)
	
	fmt.Printf("--- %s ---\n", label)
	fmt.Printf("Duration: %v\n", duration)
	fmt.Printf("GC runs: %d\n", statsAfter.NumGC-statsBefore.NumGC)
	fmt.Printf("GC time: %v\n", time.Duration(statsAfter.PauseTotalNs-statsBefore.PauseTotalNs))
	fmt.Printf("Heap allocations: %d KB\n", (statsAfter.TotalAlloc-statsBefore.TotalAlloc)/1024)
	fmt.Printf("Objects allocated: %d\n\n", statsAfter.Mallocs-statsBefore.Mallocs)
}

func main() {
	const objectCount = 100000
	
	// Measure high-pressure objects
	measureGCStats("High GC Pressure", func() {
		objects := createHighPressureObjects(objectCount)
		_ = objects // Prevent compiler optimization
	})
	
	// Measure low-pressure objects
	measureGCStats("Low GC Pressure", func() {
		objects := createLowPressureObjects(objectCount)
		_ = objects // Prevent compiler optimization
	})
}

Write Barrier Optimization

Understanding write barriers can help optimize performance in GC-heavy applications:

package main

import (
	"fmt"
	"runtime"
	"time"
)

// Structure with many pointers - more write barriers
type ManyPointers struct {
	a, b, c, d, e *int
	f, g, h, i, j *string
}

// Structure with fewer pointers - fewer write barriers
type FewerPointers struct {
	a, b, c, d, e int
	f, g, h, i, j string
}

func modifyManyPointers(obj *ManyPointers, iterations int) {
	for i := 0; i < iterations; i++ {
		// Each of these assignments triggers a write barrier during GC
		val := i
		obj.a = &val
		obj.b = &val
		obj.c = &val
		obj.d = &val
		obj.e = &val
		
		str := fmt.Sprintf("iteration-%d", i)
		obj.f = &str
		obj.g = &str
		obj.h = &str
		obj.i = &str
		obj.j = &str
	}
}

func modifyFewerPointers(obj *FewerPointers, iterations int) {
	for i := 0; i < iterations; i++ {
		// These assignments don't trigger write barriers
		obj.a = i
		obj.b = i
		obj.c = i
		obj.d = i
		obj.e = i
		
		obj.f = fmt.Sprintf("iteration-%d", i)
		obj.g = fmt.Sprintf("iteration-%d", i)
		obj.h = fmt.Sprintf("iteration-%d", i)
		obj.i = fmt.Sprintf("iteration-%d", i)
		obj.j = fmt.Sprintf("iteration-%d", i)
	}
}

func main() {
	const iterations = 1000000
	
	// Test with many pointers (more write barriers)
	manyPtrObj := &ManyPointers{}
	start := time.Now()
	modifyManyPointers(manyPtrObj, iterations)
	manyPtrDuration := time.Since(start)
	
	// Test with fewer pointers (fewer write barriers)
	fewerPtrObj := &FewerPointers{}
	start = time.Now()
	modifyFewerPointers(fewerPtrObj, iterations)
	fewerPtrDuration := time.Since(start)
	
	// Print results
	fmt.Printf("Many pointers (more write barriers): %v\n", manyPtrDuration)
	fmt.Printf("Fewer pointers (fewer write barriers): %v\n", fewerPtrDuration)
	fmt.Printf("Performance difference: %.2fx\n", 
		float64(manyPtrDuration)/float64(fewerPtrDuration))
	
	// Print GC statistics
	var stats runtime.MemStats
	runtime.ReadMemStats(&stats)
	fmt.Printf("\nGC statistics:\n")
	fmt.Printf("GC cycles: %d\n", stats.NumGC)
	fmt.Printf("Total GC pause: %v\n", time.Duration(stats.PauseTotalNs))
	fmt.Printf("GC CPU fraction: %.2f%%\n", stats.GCCPUFraction*100)
}

Memory Profiling and Debugging

Identifying and resolving memory issues requires sophisticated profiling and debugging techniques.