A memory allocation reserves storage while a program runs. In Go performance work, allocations are commonly measured as allocations per operation and bytes per operation. Heap allocations need runtime bookkeeping and garbage collection, so reducing unnecessary ones can improve memory use and latency. Treat allocation count as a measurement to investigate, not a reason to sacrifice clear, correct code. section 3.2.3 section 4.2.3 section 3.2.5
Start with evidence. Run a benchmark repeatedly with memory reporting, save a memory profile, and inspect the allocating lines with pprof. Repeated runs help reduce noise from machine load, temperature, and similar environmental variation. Compare an old and revised implementation with benchstat rather than judging a number in isolation. section 3.2.3 section 3.2.5
$ go tool pprof -list String mem.out
. . .
18.83GB 18.83GB (flat, cum) 100% of Total
. . 35:func (u *URL) String() string {
. . 36: if u == nil {
. . 37: return ""
. . 38: }
. . 39: var s string
. . 40: if sc := u.Scheme; sc != "" {
. . 41: s += sc #1
2.44GB 2.44GB 42: s += "://" #2
. . 43: }
. . 44: if h := u.Host; h != "" {
4.66GB 4.66GB 45: s += h #2
. . 46: }
. . 47: if p := u.Path; p != "" {
4.63GB 4.63GB 48: s += "/" #3
7.10GB 7.10GB 49: s += p #3
. . 50: }
. . 51: return s
. . 52:}
. . .
The profile attributes allocation volume to each string-concatenation line, making repeated rebuilding visible as the optimization target. section 3.2.3
Repeated string building
Combining strings creates new strings because strings are immutable and each combination copies data into a new underlying array. A URL String method that repeatedly uses + allocates four times. Replacing that approach with one contiguous reserved slice reduces the result to one allocation; the compared benchmark falls from 919 to 361 bytes per operation and from four to one allocation per operation. section 3.2.3 section 3.2.5
Use allocation-aware choices without assuming that pointers are always cheaper:
- Pass a configuration pointer to a function when the function can operate on the caller-owned value; this may avoid a heap allocation, but verify the compiler’s decision. section 4.2.3
- Check escape analysis with go build -gcflags="-m" to see whether a variable moves to the heap or remains on the goroutine stack. section 4.2.3
- Prefer value results when mutation and sharing are unnecessary. Value passing gives goroutines independent copies and can avoid pointer-related heap allocation and garbage-collector overhead. section 6.3.3
- Stream data when only a response size is needed. Reading an entire unknown response with io.ReadAll stores all bytes and can repeatedly grow backing arrays. section 7.3.3
Allocation reductions matter most in repeated or high-load paths. Fewer heap objects mean less work for the garbage collector; in the URL example, one allocation also keeps data contiguous, while the prior approach scattered buffers across the heap. The resulting service can use less memory and show more consistent performance under load. section 3.2.5










