Go Memory Management — Optimize¶
Exercise 1 🟢 — Pre-Allocate Slice Cap¶
Saves ~log2(N) reallocations.
Exercise 2 🟢 — Pre-Allocate Map Size¶
Avoids progressive rehashing.
Exercise 3 🟡 — sync.Pool for Hot Allocation¶
var pool = sync.Pool{New: func() any { return new(Buffer) }}
func use() {
b := pool.Get().(*Buffer)
defer func() { b.Reset(); pool.Put(b) }()
// use b
}
Reduces alloc rate; lower GC frequency.
Exercise 4 🟡 — Reduce Pointer Density¶
// Bad
type Events struct { items []*Event }
// Good (when ownership exclusive)
type Events struct { items []Event }
Fewer GC roots; better cache locality.
Exercise 5 🟡 — Set GOMEMLIMIT for Containers¶
Prevents OOM by triggering more aggressive GC near the limit.
Exercise 6 🔴 — Subslice Copy to Release Backing¶
Returns independent slice; backing array can be GC'd.
Exercise 7 🔴 — Periodic Map Rebuild¶
type Cache struct {
mu sync.Mutex
m map[K]V
deletes int
}
func (c *Cache) Delete(k K) {
c.mu.Lock(); defer c.mu.Unlock()
delete(c.m, k)
c.deletes++
if c.deletes > len(c.m) {
// recreate map to release old buckets
newM := make(map[K]V, len(c.m))
for k, v := range c.m { newM[k] = v }
c.m = newM
c.deletes = 0
}
}
Exercise 8 🔴 — Profile and Optimize Top Allocator¶
Find hot allocation site. Apply: - Pre-allocation. - sync.Pool. - Reduce pointer density. - Inline value-typed.
Re-benchmark; verify improvement.
Exercise 9 🔴 — Verify Inlining Eliminates Allocation¶
Run go build -gcflags="-m". If tiny is inlined into a caller that doesn't escape, n may stay on stack.
For inlining: keep functions small; avoid defer, complex control flow.
Exercise 10 🔴 — atomic.Pointer for Lock-Free Snapshot¶
import "sync/atomic"
var configPtr atomic.Pointer[Config]
func get() *Config { return configPtr.Load() }
func reload() { configPtr.Store(loadConfig()) }
Lock-free reads; readers see consistent snapshots without locking.