Go的内存对齐

一、基础数据类型占用内存

unsafe.Sizeof()

类型字节数
bool1
string2 * 计算机字长/8 (64位16个字节,32位8个字节)
int、uint、uintptr计算机字长/8 (64位8个字节,32位4个字节)
*T, map, func, chan计算机字长/8 (64位8个字节,32位4个字节)
intN, uintN, floatN, complexNN/8个字节(int32是4个字节,float64是8个字节)
interface2 * 计算机字长/8 (64位16个字节,32位8个字节)
[]T3 * 计算机字长/8 (64位24个字节,32位12个字节)
二、什么是内存对齐

各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐

三、为什么需要内存对齐
  • 不同硬件平台的cpu读取内存方式具有差异性,内存对其可以帮助代码的平台移植性
  • cpu访问内存不是一个个字节去读取的,而是以字长为单位去读取的,32位操作系统是4个字节,64位操作系统是8个字节,如果没有对齐内存,会导致一个变量可能需要多次读取才能获得完整数据,不利于原子性处理
四、结构体对齐过程
对齐系数 = min(计算机字长/8,unsafe.Sizeof(x))
对于任意类型的变量 x ,unsafe.Alignof(x) 至少为 1;
对于 struct 结构体类型的变量 x,计算 x 每一个字段 f 的 unsafe.Alignof(x.f),unsafe.Alignof(x) 等于其中的最大值;
对于 array 数组类型的变量 x,unsafe.Alignof(x) 等于构成数组的元素类型的对齐倍数。
func main() {
	fmt.Println(unsafe.Sizeof(MemStruct{}), unsafe.Alignof(MemStruct{})) //8 4
	fmt.Println(unsafe.Sizeof(MemStruct1{}), unsafe.Alignof(MemStruct1{})) //12 4
	fmt.Println(unsafe.Sizeof(MemStruct2{}), unsafe.Alignof(MemStruct2{})) //24 8
}

type MemStruct struct {
	b   bool  // 1
	i8  int8  // 1
	i16 int16 // 2
	i32 int32 // 4
}

type MemStruct1 struct {
	b   bool  // 1
	i32 int32 // 4
	i8  int8  // 1
}

type MemStruct2 struct {
	b   bool  // 1
	i8  int8  // 1
	i64 int64 // 8
}

S1 明显占用的内存更少。让我们来分析一下,S1 和 S2 的对齐系数都等于其子字段 int16 的对齐系数,也就是 4。对于S1,经过内存对齐,它们在内存中的布局是这样的:

img

对于 S1:

  • i8 是第一个字段,默认已经对齐,从 0 开始占据 1 个字节;
  • i16 是第二个字段,对齐系数为 2,因此,必须填充 1 个字节,其偏移量才是 2 的倍数,从 2 开始占据 2 字节;
  • i32 是第三个字段,对齐系数为 4,此时,内存已经是对齐的,从第 4 开始占据 4 字节即可;

因此 S1 在内存占用了 8 个字节,浪费了 1 个字节。

对于 S2:

  • i8 是第一个字段,默认已经对齐,从 0 开始占据 1 个字节;
  • i32 是第二个字段,对齐系数为 4,因此,必须填充 3 个字节,其偏移量才是 4 的倍数,从第 4 开始占据 4 字节;
  • i16 是第三个字段,对齐系数为 2,此时,内存已经是对齐的,从第 8 开始占据 2 字节即可。

因此 S2 在内存占用了 12 个字节,浪费了 5 个字节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值