Understanding Go Memory Alignment: A Complete Guide
This article explains Go’s type size specifications and alignment guarantees, demonstrates how to compute a struct’s memory footprint using unsafe.Sizeof and unsafe.Alignof, walks through concrete examples with structs T and R, and shows how field ordering affects actual memory usage.
Type Sizes
According to the Go language specification, the basic numeric types have the following fixed sizes (in bytes):
type size in bytes
byte, uint8, int8 1
uint16, int16 2
uint32, int32, float32 4
uint64, int64, float64, complex64 8
complex128 16
uint, int either 32 or 64 bits depending on the target architecture
uintptr an unsigned integer large enough to hold a pointer valueOn a 64‑bit system, uint and int are 8 bytes; on a 32‑bit system they are 4 bytes.
Getting Type Sizes in Code
func main() {
var i bool = true
var j int = 40
fmt.Println("bool-size", unsafe.Sizeof(i))
fmt.Println("int-size", unsafe.Sizeof(j))
}Running the program on a 64‑bit machine prints:
bool-size 1
int-size 8Alignment Guarantees
Alignment guarantee (also called value‑address alignment) means that a variable’s start address is always a multiple of its alignment value.
The Go spec defines the minimal alignment properties as:
1. For any variable x, unsafe.Alignof(x) ≥ 1.
2. For a struct variable x, unsafe.Alignof(x) is the largest unsafe.Alignof of its fields (minimum 1).
3. For an array variable x, unsafe.Alignof(x) equals the alignment of the array’s element type.Getting Alignment in Code
func main() {
var i bool = true
var j int = 40
fmt.Println("bool-align", unsafe.Alignof(i)) // general alignment
fmt.Println("int-align", unsafe.Alignof(j))
type temp struct {
a bool
b int
}
var tmp = temp{}
fmt.Println("a", unsafe.Alignof(tmp.a)) // field alignment
fmt.Println("b", unsafe.Alignof(tmp.b))
}Output on a 64‑bit system:
bool-align 1
int-align 8
a 1
b 8Practical Example – Struct T
type T struct {
a bool
b int8
c uint16
d uint32
e int64
f bool
}
func main() {
var t = T{}
fmt.Println("size", unsafe.Sizeof(t), "align", unsafe.Alignof(t))
fmt.Println("a", unsafe.Sizeof(t.a), "align", unsafe.Alignof(t.a), "offset", unsafe.Offsetof(t.a))
fmt.Println("b", unsafe.Sizeof(t.b), "align", unsafe.Alignof(t.b), "offset", unsafe.Offsetof(t.b))
fmt.Println("c", unsafe.Sizeof(t.c), "align", unsafe.Alignof(t.c), "offset", unsafe.Offsetof(t.c))
fmt.Println("d", unsafe.Sizeof(t.d), "align", unsafe.Alignof(t.d), "offset", unsafe.Offsetof(t.d))
fmt.Println("e", unsafe.Sizeof(t.e), "align", unsafe.Alignof(t.e), "offset", unsafe.Offsetof(t.e))
fmt.Println("f", unsafe.Sizeof(t.f), "align", unsafe.Alignof(t.f), "offset", unsafe.Offsetof(t.f))
}Running the program yields:
size 24 align 8
a 1 align 1 offset 0
b 1 align 1 offset 1
c 2 align 2 offset 2
d 4 align 4 offset 4
e 8 align 8 offset 8
f 1 align 1 offset 16Summing the field sizes (1+1+2+4+8+1) gives 17 bytes, which is smaller than the reported struct size of 24 bytes. The discrepancy is caused by two padding rules:
Each field’s start address must be a multiple of its alignment.
The total size of the struct must be a multiple of the struct’s own alignment (the maximum field alignment, here 8 bytes).
After placing the fields according to their alignment, 7 bytes of padding are inserted after field f to bring the total size to the next multiple of 8, resulting in 24 bytes.
Effect of Field Ordering – Struct R
Reordering the fields (placing the larger uint32 before the uint16) produces a different layout:
type R struct {
a bool
b int8
d uint32
c uint16
e int64
f bool
}Running the same inspection code on R prints:
size 32 align 8
a 1 align 1 offset 0
b 1 align 1 offset 1
d 4 align 4 offset 4
c 2 align 2 offset 8
e 8 align 8 offset 16
f 1 align 1 offset 24Because the 4‑byte field d is placed before the 2‑byte field c, the compiler inserts additional padding to keep each field aligned, resulting in a total size of 32 bytes instead of 24.
Placing larger fields after smaller ones can increase the overall memory consumption of a struct.
Conclusion
Inspecting unsafe.Sizeof, unsafe.Alignof, and unsafe.Offsetof shows that Go’s type size table and alignment guarantees determine the actual memory layout of structs. Field ordering influences padding and total size. In most everyday code the compiler handles alignment automatically, but when memory usage is critical, arranging fields from largest to smallest can reduce wasted space.
Source code repository: https://github.com/gofish2020/zeus/tree/main/source/memoryalign
References:
https://golang.google.cn/ref/spec#Size_and_alignment_guarantees
https://golang.google.cn/ref/spec#Numeric_types
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Nullbody Notes
Go backend development, learning open-source project source code together, focusing on simplicity and practicality.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
