Go Pointers Basics โ Optimize¶
Instructions¶
Each exercise presents inefficient pointer usage. Identify the issue, fix it. Difficulty: ๐ข ๐ก ๐ด.
Exercise 1 ๐ข โ Returning Pointer When Value Suffices¶
Problem:
For small types, this allocates per call. Fix โ return value:
Benchmark: pointer ~20 ns/op + 1 alloc; value ~3 ns/op + 0 alloc.
Key insight: For small types, return value. Pointer return forces heap.
Exercise 2 ๐ข โ Unnecessary Pointer Argument¶
Problem:
Just pass the value:
For primitives, value pass is faster (register, no indirection).
Exercise 3 ๐ก โ Pool Heavy Allocations¶
Problem: A function allocates a 1 KB buffer per call.
Fix โ sync.Pool:
var pool = sync.Pool{New: func() any { return new([1024]byte) }}
func use() {
buf := pool.Get().(*[1024]byte)
defer pool.Put(buf)
// use buf
}
Benchmark: ~50ร fewer allocations.
Exercise 4 ๐ก โ Use atomic.Pointer Instead of Mutex for Snapshot¶
Problem:
var mu sync.RWMutex
var config *Config
func get() *Config {
mu.RLock(); defer mu.RUnlock()
return config
}
Fix โ atomic.Pointer:
Lock-free reads; faster under high concurrency.
Exercise 5 ๐ก โ Reduce Pointer Density¶
Problem: []*Item for 1M items adds 1M GC roots.
Fix โ []Item (slice of values):
Each item inline; better cache locality; fewer GC roots.
When pointers ARE needed (sharing): keep them; otherwise prefer values.
Exercise 6 ๐ด โ Atomic.Pointer for Snapshot Config¶
Problem: Reload config without locking readers.
import "sync/atomic"
type Config struct { /* ... */ }
var current atomic.Pointer[Config]
func init() {
current.Store(loadConfig())
}
func reload() {
new := loadConfig()
current.Store(new) // lock-free swap
}
func handle() {
cfg := current.Load() // safe snapshot
// use cfg
}
Old configs become garbage when all readers finish; GC handles cleanup.
Exercise 7 ๐ด โ Verify Stack Allocation¶
Problem:
Does new(int) heap-allocate?
Verify:
If you see "moved to heap", investigate. For simple cases, escape analysis keeps it on the stack.
Exercise 8 ๐ด โ Avoid Pointer Aliasing in Hot Path¶
Problem:
Each iteration must reload *a because the compiler can't prove a != b.
Fix โ load to register first:
Benchmark: ~10ร speedup for memory-bound loop.
Key insight: Pointer aliasing limits compiler optimization. Hoist loads/stores.
In this topic