Go 语言和 C 语言类似,结构体的成员必须按照它们的对齐要求存储。编译器会自动填充对齐字节,确保每个字段的起始地址符合 CPU 的对齐规则。
示例
            
            
              go
              
              
            
          
          package main
import (
    "fmt"
    "unsafe"
)
type A struct {
    a int8
    b uint32
    c int16
}
func main() {
    fmt.Printf("Offsetof(A.a) = %d\n", unsafe.Offsetof(A{}.a))
    fmt.Printf("Offsetof(A.b) = %d\n", unsafe.Offsetof(A{}.b))
    fmt.Printf("Offsetof(A.c) = %d\n", unsafe.Offsetof(A{}.c))
    fmt.Printf("Sizeof(A) = %d\n", unsafe.Sizeof(A{}))
}
/*
Output:
Offsetof(A.a) = 0
Offsetof(A.b) = 4
Offsetof(A.c) = 8
Sizeof(A) = 12
*/
        内存布局
因为 b 需要4字节对齐,所以编译器会在 a 之后填充3个字节。又因为结构体的大小必须是其最大对齐方式(4字节)的整数倍,所以最终结构体 A 的大小为12个字节。
优化
            
            
              go
              
              
            
          
          package main
import (
    "fmt"
    "unsafe"
)
type AOptimized struct {
    a int8
    c int16
    b uint32
}
func main() {
    fmt.Printf("Offsetof(AOptimized.a) = %d\n", unsafe.Offsetof(AOptimized{}.a))
    fmt.Printf("Offsetof(AOptimized.b) = %d\n", unsafe.Offsetof(AOptimized{}.b))
    fmt.Printf("Offsetof(AOptimized.c) = %d\n", unsafe.Offsetof(AOptimized{}.c))
    fmt.Printf("Sizeof(AOptimized) = %d\n", unsafe.Sizeof(AOptimized{}))
}
        优化后内存布局
因为 c 需要2字节对齐,所以编译器会在 a 之后填充1个字节。此时结构体的实际大小为8个字节,刚好是最大对齐方式(4字节)的整数倍,所以最终结构体 A 的大小为8个字节。
结论
Go 结构体需要关注对齐
- 和 C 语言一样,Go 结构体会自动填充来对齐字段。
 - 不合理的字段排列会浪费内存。
 - 使用 
unsafe.Sizeof()和unsafe.Offsetof()了解结构体的内存布局。 
结构体优化可以减少内存占用
- 合理排序字段,减少填充。
 
合理优化结构体,可以减少内存占用,提高 Go 程序的性能!