How does struct field ordering affect memory usage and performance?
Each field is aligned to its type's alignment (int64/pointers: 8 on 64-bit), and the struct's size is rounded up to its largest alignment. Poor ordering inserts padding.
type Bad struct {
Active bool // 1 + 7 padding
ID int64 // 8
Admin bool // 1 + 7 padding
} // unsafe.Sizeof == 24
type Good struct {
ID int64 // 8
Active bool // 1
Admin bool // 1 + 6 padding
} // unsafe.Sizeof == 16
func main() {
fmt.Println(unsafe.Sizeof(Bad{}), unsafe.Sizeof(Good{})) // 24 16
}
For a slice of 10 million elements that's 80 MB saved and better cache utilization. Rule of thumb: order fields from largest to smallest alignment. The fieldalignment analyzer (golang.org/x/tools/go/analysis/passes/fieldalignment) reports both wasted bytes and "pointer bytes" — putting pointer fields first shortens the prefix the GC must scan.
Gotchas: don't blindly reorder everything — group fields by readability unless the struct is allocated in large numbers or is on a hot path. atomic.Int64 guarantees 8-byte alignment even on 32-bit platforms, which is why it's preferred over a raw int64 with atomic.AddInt64 (which requires manual alignment on 386/ARM). A zero-size field at the end of a struct adds padding so its address doesn't point past the object.
More on Performance, Profiling & Testing
- Q395Why does preallocating slices and maps matter? What does this print?
- Q396What is false sharing and how would you detect and fix it in Go?
- Q398How can you convert between []byte and string without allocating? When is it safe?
- Q399How does the race detector work, what does it cost, and what are its limits?
- Q400How do you separate unit tests from slow integration tests, and what are golden files?
- Q401What are Example functions, and how are they verified?