Map internals and performance
Treat Go maps as an abstraction for correctness, but use implementation details to form measured performance hypotheses when map-heavy code is hot.
Canonical guidance
- rely on documented map semantics for correctness, not runtime internals
- use internal knowledge only to form performance hypotheses
- benchmark before changing key types, preallocation, or data structures
- prefer ordinary maps until measurement shows a real bottleneck
Use when
- profiling map-heavy hot paths
- investigating unexpected allocations or CPU in lookup-heavy code
- deciding whether map preallocation or alternative structures are justified
Avoid
- depending on bucket behavior, growth details, or iteration internals in program logic
- replacing clear map-based code with custom structures before measuring
- cargo-cult sharding or hash precomputation with no profile evidence
Preferred pattern
counts := make(map[string]int, expected)
for _, item := range items {
counts[item.Key]++
}
Anti-pattern
- redesigning working code around guessed map internals because a workload “feels” map-bound
Explanation: This anti-pattern is tempting because runtime details sound precise, but map-heavy performance work still needs real profiles and benchmarks.
Why
- map internals can explain behavior, but they are a poor substitute for measurement
- implementation details may evolve across Go releases even when language-level semantics stay stable
Related pages
Sources
- Go maps in action - Andrew Gerrand
- How the Go runtime implements maps efficiently (without generics) - Dave Cheney
- Diagnostics - Go Team