type T1 struct {
a [2]int8
b int64
c int16
}
type T2 struct {
a [2]int8
c int16
b int64
}
fmt.Printf("arrange fields to reduce size:\n"+
"T1 align: %d, size: %d\n"+
"T2 align: %d, size: %d\n",
unsafe.Alignof(T1{}), unsafe.Sizeof(T1{}),
unsafe.Alignof(T2{}), unsafe.Sizeof(T2{}))
/*
output:
arrange fields to reduce size:
T1 align: 8, size: 24
T2 align: 8, size: 16
*/
/*
以64位系统为例,分析如下:
T1,T2内字段最大的都是int64, 大小为8bytes,对齐按机器字确定,64位下是8bytes,所以将按8bytes对齐
T1.a 大小2bytes,填充6bytes使对齐(后边字段已对齐,所以直接填充)
T1.b 大小8bytes,已对齐
T1.c 大小2bytes,填充6bytes使对齐(后边无字段,所以直接填充)
总大小为 8+8+8=24
T2中将c提前后,a和c总大小4bytes,在填充4bytes使对齐
总大小为 8+8=16
*/
零大小字段不要放在最后
type T1 struct {
a struct{}
x int64
}
type T2 struct {
x int64
a struct{}
}
a1 := T1{}
a2 := T2{}
fmt.Printf("zero size struct{} in field:\n"+
"T1 (not as final field) size: %d\n"+
"T2 (as final field) size: %d\n",
// 8
unsafe.Sizeof(a1),
// 64位:16;32位:12
unsafe.Sizeof(a2))
内存地址对齐
unsafe包规范中说明如果类型t的对齐保证是n,那么类型t的每个值的地址在运行时必须是n的倍数
一个典型示例是
type WaitGroup struct {
noCopy noCopy
state1 [3]uint32
}
// state returns pointers to the state and sema fields stored within wg.state1.
func (wg *WaitGroup) state() (statep *uint64, semap *uint32) {
// 判定地址是否8位对齐
if uintptr(unsafe.Pointer(&wg.state1))%8 == 0 {
// 前8bytes做uint64指针statep,后4bytes做sema
return (*uint64)(unsafe.Pointer(&wg.state1)), &wg.state1[2]
} else {
// 后8bytes做uint64指针statep,前4bytes做sema
return (*uint64)(unsafe.Pointer(&wg.state1[1])), &wg.state1[0]
}
}