目录

内存对齐

目录

计算机总线中有一个 数据总线,用来传输内存上的数据到寄存器中,数据总线大小决定了一次能传输多个数据,比如32位总线一次能传输4字节,字长就是4字节,如果需要取一个8字节的数据就需要传输两次,64位总线一次能传输8字节,字长就是8字节,取一个8字节的数据只需要一次传输即可,所以CPU取数据都是以数据总线宽度(也就是CPU字长)为单位来取的

内存对齐就是为了提高CPU获取数据的效率,如果不进行内存对齐可能会增加CPU访问数据的次数

|a|a|a|b|b|b| | | #对齐前
|a|a|a| |b|b|b| | #对齐后

比如a、b各自占用3byte,CPU字长为4byte,不进行内存对齐而采用紧凑的方式存储那么访问a只需要一次,但是访问b就需要进行两次

并且一个struct的起始地址也是需要从CPU字长的整数倍开始的,同时如果一个struct的长度不足自身内存对齐边界(属性中长度最长的那个)的整数倍则会进行填充,这是为了在数组中保持struct依然是内存对齐的

因为struct会进行内存对齐,所以我们需要合理的布局struct中各个属性的分布,这样才能有效的减少内存大小

type A struct {
	a int8
	b int16
	c int32
}

type B struct {
	a int8
	c int32
	b int16
}

type C struct {
	a int32
	c int64
	b int8
}

type D struct {
	c int64
	a int32
	b int8
}

func main() {
	fmt.Println(unsafe.Sizeof(A{})) // 8
	fmt.Println(unsafe.Sizeof(B{})) // 12
	fmt.Println(unsafe.Sizeof(C{})) // 24
	fmt.Println(unsafe.Sizeof(D{})) // 16
}

在Go中需要结算struct中对齐边界最大的值作为整个结构体的对齐边界

参考

https://geektutu.com/post/hpg-struct-alignment.html

https://www.bilibili.com/video/BV1hv411x7we?p=3