Does converting a value to an interface allocate? How do interfaces affect escape analysis and performance?
Question 100HardGo 1.22 to 1.25
Often it does. The data word must be a pointer, so non-pointer values are copied into memory. The runtime helpers (convT, convT64, convTstring) allocate on the heap unless one of these holds:
- The value is already pointer-shaped (
*T, map, chan, func). - The value is zero-sized.
- The value is a constant or a small integer under 256 (the runtime uses the static array
staticuint64s). - Escape analysis proves the interface does not escape, so the copy can live on the stack.
var sink any // package-level, so the boxed value escapes
func BenchmarkBox(b *testing.B) {
for i := range b.N {
sink = i + 1000 // 1 alloc/op (8 B): int above 255 boxed on heap
}
}
// With a local sink the interface would not escape, the box would live on
// the stack, and the benchmark would report 0 allocs/op.
// Check what escapes:
// go build -gcflags='-m' ./...
// ./x.go:12:9: i + 1000 escapes to heap
Calling through an interface also hides the callee from the compiler. Arguments passed to interface methods are usually assumed to escape. That is why fmt.Println(x) makes x escape, and why w.Write(buf) through an io.Writer forces buf onto the heap.
Ways to mitigate in hot paths:
- Use concrete types or generics. GC-shape stenciling still uses dictionaries, but it avoids boxing.
- Pass pointers.
- Avoid
any-based variadic loggers in tight loops, or useslog's typedAttrhelpers. - Enable PGO so hot call sites get devirtualized.
Always measure with -benchmem before optimising.
More on Interfaces, Methods & Embedding
- Q98Design custom errors in Go. Explain wrapping,
errors.Is,errors.Asand multi-error trees. - Q99When does comparing two interface values panic? What does this print?
- Q101What's the difference between a method value and a method expression? What does this print?
- Q102On which types can you declare methods? Can you add a method to
int,time.Time, a pointer type, or an interface? - Q103How does the "optional interface" (interface upgrade) pattern work? Give a stdlib example and its pitfall.
- Q104How do constraint interfaces in generics differ from ordinary interfaces?