Escape Analysis & Alignment
Escape Analysis & Memory Alignment
Memory optimization usually comes down to two questions: 1. Did it hit the heap when it didn’t need to? (Excessive allocation) 2. Is it wasting space? (Poor alignment)
Part 1: Escape Analysis
“Escape Analysis” is the compiler phase that decides Stack vs. Heap.
Asking the Compiler
You don’t need to guess. Ask the compiler what it decided:
go build -gcflags="-m" main.goOutput Interpretation: * can inline main: Good. * x does not escape: Great (Stack). * moved to heap: x: Bad (Heap).
Common Escape Triggers
- Returning Pointers:
func New() *T { return &T{} }-> Escapes. - Interfaces:
func Log(v interface{}). The concrete type inside the interface box often escapes. - Closures: Variables captured by a closure might escape if the closure outlives the function.
- Unknown Size:
make([]int, n)always escapes ifnis dynamic.
The “Mid-Stack” Trick
If you need a large buffer inside a hot loop, allocate it once outside the loop or reuse a sync.Pool. * Bad: for { b := make([]byte, 1024); process(b) } (Trash on heap every loop) * Better: b := make([]byte, 1024); for { process(b) } (One alloc) * Best (Stack): b := [1024]byte{}; for { process(b[:]) } (Stack alloc if small enough)
Part 2: Memory Alignment (Padding)
CPU reads memory in words (e.g., 64-bit / 8 bytes). If a field doesn’t align with a word boundary, the compiler adds Padding (wasted bytes).
The Struct Layout Game
Consider this struct:
type BadStruct struct {
Flag bool // 1 byte
Counter int64 // 8 bytes
Active bool // 1 byte
}Total Size: * bool (1) + padding (7) -> to align int64 * int64 (8) * bool (1) + padding (7) -> to align struct size to 8 * Total: 24 bytes
Reshuffled:
type GoodStruct struct {
Counter int64 // 8 bytes (0-7)
Flag bool // 1 byte (8)
Active bool // 1 byte (9)
// padding (6) -> to align struct size to multiple of 8 (16)
}Total: 16 bytes. 33% savings just by reordering fields.
Tools used in 2026
Do not optimize manually unless you are bored. Use tools.
fieldalignment:bash go install golang.org/x/tools/go/analysis/passes/fieldalignment/cmd/fieldalignment@latest fieldalignment ./...It will report structs that use too much memory and suggest a fix.betteralign: A more modern wrapper that can automatically apply changes (-apply).
When does this matter?
- Single struct: Who cares? 8 bytes is nothing.
- Slice of 100 million structs: 8 bytes * 100M = 800MB of RAM wasted. This triggers GC more often, costs money on cloud bills, and slows down cache.
Rule: Optimize alignment for “Data Types” (things you store in DB/Arrays). Ignore it for “Service Types” (singletons, handlers).