Golang结构体内存布局

✅ 一句话总结:

Go 的结构体不是简单相加大小,而是根据对齐规则填充 padding(填充字节),最终大小必须是最大对齐值的倍数。

为什么要关心对齐

  • 你正在编写的代码在性能(CPU、Memory)方面有一定的要求
  • 你正在处理向量方面的指令
  • 某些硬件平台(ARM)体系不支持未对齐的内存访问

为什么要做对齐

  • 平台(移植性)原因:不是所有的硬件平台都能够访问任意地址上的任意数据。例如:特定的硬件平台只允许在特定地址获取特定类型的数据,否则会导致异常情况
  • 性能原因:若访问未对齐的内存,将会导致 CPU 进行两次内存访问,并且要花费额外的时钟周期来处理对齐及运算。而本身就对齐的内存仅需要一次访问就可以完成读取动作

在上图中,假设从 Index 1 开始读取,将会出现很崩溃的问题。因为它的内存访问边界是不对齐的。因此 CPU 会做一些额外的处理工作。如下:

  1. CPU 首次读取未对齐地址的第一个内存块,读取 0-3 字节。并移除不需要的字节 0
  2. CPU 再次读取未对齐地址的第二个内存块,读取 4-7 字节。并移除不需要的字节 5、6、7 字节
  3. 合并 1-4 字节的数据
  4. 合并后放入寄存器

从上述流程可得出,不做 “内存对齐” 是一件有点 "麻烦" 的事。因为它会增加许多耗费时间的动作

而假设做了内存对齐,从 Index 0 开始读取 4 个字节,只需要读取一次,也不需要额外的运算。这显然高效很多,是标准的空间换时间做法

一、先看结构体定义

type Test struct {
    a bool   // 1
    b int32  // 4
    c int8   // 1
    d int64  // 8
    e byte   // 1
}

单独大小确实是:
1 + 4 + 1 + 8 + 1 = 15 字节

但 Go 不允许你这样省空间,因为「对齐」。

二、对齐规则最容易误解,看我简化后的版本

对齐规则(简化版)

① 每个字段必须放在 它对齐值的整数倍偏移地址上

类型

大小

对齐值

bool

1

1

int8

1

1

byte

1

1

int32

4

4

int64

8

8

② 结构体整体大小必须是 最大对齐值(这里是 8) 的整数倍

三、按顺序计算内存布局(会发现 padding 出现了)

⭐ 步骤 1:字段 a(bool)

字段

对齐值

当前偏移

可放?

放到偏移

占用

a

1

0

0 % 1 = 0 ✔

0

1B

⭐ 步骤 2:字段 b(int32)

b 对齐值是 4
当前 offset=1
1 不是 4 的倍数,必须填 padding,填到 4 位置。

所以需要补:4 - (1 % 4) = 3 字节

填充

新偏移

+3

offset = 4

然后放 b,占 4 字节:

offset = 4 + 4 = 8

⭐ 步骤 3:字段 c(int8)

int8 对齐值 = 1 → 没问题

c 放在 offset 8,占 1 字节

offset = 9

⭐ 步骤 4:字段 d(int64)

对齐值 8
当前 offset=9
但 9 % 8 = 1 ≠ 0
需要补齐到下一个 8 对齐地址:16

16 - 9 = 7 字节 padding

offset = 16

放 d,占 8 字节:

offset = 16 + 8 = 24

⭐ 步骤 5:字段 e(byte)

byte 对齐值=1,无需对齐

放在 offset=24,占 1 字节

offset = 25

⭐ 步骤 6:结构体整体对齐

结构体的对齐值 = 最大字段对齐值 = 8

但当前结构体大小=25
必须让 25 补齐到 8 的倍数:

下一个 8 的倍数是 32

所以需要额外 padding:
32 - 25 = 7 字节

最终结构体大小 = 32 字节

🎉 四、你看到的最终 layout(图示)

a xxx | bbbb | c xxx | xxx | dddd dddd | e xxx | xxx
0     4      8       16      24        25     32(end)

更清晰一点(每段代表 4 字节):

[ a . . . ] [ b b b b ] [ c . . . ] [ . . . . ]
[ d d d d ] [ d d d d ] [ e . . . ] [ . . . . ]

. 表示 padding(填充字节)

五、实验输出结果

Test size: 32, align: 8

六、为什么 Go 有这种对齐机制?

为了 CPU 高效访问内存。
CPU 访问 misaligned memory(未对齐地址)速度会变慢,甚至在某些平台会直接报错。

所以 Go 编译器自动对齐字段,让结构体在内存中更高效。

如果想让结构体更节省空间怎么办?

👉 调整字段顺序(从大到小)

type Test2 struct {
    d int64
    b int32
    a bool
    c int8
    e byte
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小信啊啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值