内存对齐这个事儿只能自己搞明白
高速公路VS内存
图1. 可以把内存比作汽车高速公路
图2.
1 | package main |
输出
4
4
我们可以看到2个struct,size都是4, 2个结构体字段大小不同,但是结构体大小一样。
内存对齐
可以看到第2个int32跨了2个64位的边界,如果你是64位系统,那么CPU每次访问内存,都是拿64位这么多的数据,对于第2个int32跨越2个64位,那么cpu就要分2次拿数据。
好处
- 提高访问效率
- 提高内存原子性访问(从CPU角度看,一次操作,就搞定了)
对齐系数
1 | fmt.Printf("int64 size:%d align:%d\n", unsafe.Sizeof(int64(1)), unsafe.Alignof(int64(1))) |
int64 size:8 align:8
int32 size:4 align:4
int16 size:2 align:2
int8 size:1 align:1
string size:16 align:8
bool size:1 align:1
byte size:1 align:1
可以看到上面这些基础类型的size和对齐系数是一致的,我们要拿到一个64bit地址,能被这个对齐系数整除的,比如我们要给int16,那么地址可以是 0,2,4,8,这些都可以被2整除。
结构体对齐
**内部对齐规则:**结构体内部每个成员的偏移量自身大小与其对其系数较小值的倍数
1 | type todo struct { |
bool 大小1,对齐系数1
string 大小16,对齐系数8
int32 大小4,对齐系数4
可以看到bool占据了一个字节byte,后面都是用0填充,其他的2个字段name和id都是正常占位,在内存中,这3段是连续的。你可能会说bool后面的0都浪费了,为什么不用id去填充,因为结构体顺序是那样写的,不可以把id放到bool的后面,除非改变结构体的内部顺序。
**长度填充规则:**最大成员长度与系统字长较小的整数倍
1 | type todo struct { |
bool 大小1,对齐系数1
string 大小16,对齐系数8
int32 大小4,对齐系数4
最长成员是name,string,16字节,本系统是mac的64位,也就是8字节byte,取最小就是8个字节的整数倍。
空结构体
1 | type todo2 struct { |
看到空结构体在字段中间,没有问题
1 | type todo3 struct { |
如果最后一个字段是空结构体,那么刚刚赶上是一个字长,比如是64位系统,那么多出来这么一个空结构体,就会顺延占用位置,会导致内存的浪费,这点要注意。
如何学习Go语言微服务,快速步入架构师
添加微信 | 公众号更多内容 |
---|---|