How do you measure and assert allocation counts?
Question 346MediumGo 1.22 to 1.25
In benchmarks, call b.ReportAllocs() or run with -benchmem to get B/op and allocs/op. Since Go 1.24, prefer b.Loop(). It resets the timer automatically and keeps the loop body from being optimised away.
func BenchmarkKey(b *testing.B) {
b.ReportAllocs()
buf := make([]byte, 0, 64)
for b.Loop() {
buf = keyB(buf[:0], 42, "user")
}
}
// Unit test that guards against allocation regressions
func TestKeyNoAlloc(t *testing.T) {
buf := make([]byte, 0, 64)
allocs := testing.AllocsPerRun(100, func() {
buf = keyB(buf[:0], 42, "user")
})
if allocs != 0 {
t.Fatalf("keyB allocates %.1f times per call", allocs)
}
}
Compare runs with benchstat old.txt new.txt over -count=10 samples; a single run is noise. To find where allocations happen, run go test -bench . -memprofile mem.out, then go tool pprof -sample_index=alloc_objects mem.out and use list FuncName.
Gotcha: with the old for i := 0; i < b.N; i++ loop, unused results could be dead-code eliminated, which shows up as a fake "0 allocs, 0.3 ns/op".
More on Memory, GC & Runtime Internals
- Q344What techniques do you use to reduce allocations in a hot path?
- Q345How does
sync.Poolbehave, and what are its pitfalls? - Q347When does converting between
stringand[]byteNOT allocate? - Q348What does this print on a 64-bit platform, and why?
- Q349Explain 64-bit atomic alignment and false sharing. How do you lay out hot concurrent counters?
- Q350What are zero-sized types' memory semantics? What do these print?