什么是内存对齐
CPU在访问内存的时候,并不是一个字节一个字节读取,而是以字长(word size)为单位访问。32位CPU字长为4字节,64位CPU字长是8字节。32CPU访问内存的时候只能以4的倍数的内存开始地址读取。如果一个变量存储在跨字长的内存区域上,CPU就需要多次访问内存才能读取。
Golang为了尽量避免这种跨字长的内存访问,在内存分配时会做一次内存对齐。
内存对齐示例
1 | type Foo struct { |
输出结果
1 | Foo.a size: 1 |
理论上Foo
有三个字段,各个长度相加应该是1 + 4 + 4 = 9
通过输出我们看到它实际占用的空间是12
,这就是内存对齐的结果
内存对齐规则
- 每个平台的编译器都有一个默认的对齐系数,对齐系数可以通过预编译命令#pragma pack(n)来修改
- 结构体的成员变量对齐值等于成员变量大小和对齐系数较小的数
value = min(size, n)
- 结构体第一个成员变量偏移量是0, 后面的成员变量偏移量必须是成员变量对齐值的整数倍
- 结构体本身的对齐值是成员变量对齐值的最大值
我们再看一下上面的对齐示例
1 |
|
空结构体对齐
在Golang中空结构体struct{}
大小为0,不占用内存空间,理论上他不需要对齐,但是当空结构体是最后一个成员变量时也需要内存对齐,因为如果有指针指向该成员变量的话,空结构体也需要一个地址,CPU访问这个地址的时候也需要按字来访问
验证代码
1 | type Foo struct { |