Go Struct内存对齐
1 为什么需要考虑内存对齐
CPU访问内存时,并不是逐个字节访问,而是以字长来访问。字长是指在同一时间内处理二进制数的位数。32位系统的字长为32位,即4字节,64位系统的字长为64位,即8字节。
CPU以字长访问内存,可以减少访问次数,增加吞吐量。以32位系统为例,访问一个8字节的数据,一次读取4个字节,只需要访问2次。
2 如何计算结构体的内存空间
在Go中,可以使用unsafe.Sizeof()
来计算一个数据类型实例所占用的内存大小。
|
|
运行上面的例子,将输出:
|
|
以64位系统为例,Go语言中基本数据类型所占内存大小如下:
数据类型 | 内存大小 |
---|---|
Int8, uint8, byte, bool | 1 |
int16, uint16 | 2 |
int32, uint32, float32,rune | 4 |
int, uint,int64, uint64, float64 | 8 |
string | 16 |
3 struct如何内存对齐
3.1 合理的布局减少内存占用
假设一个结构体只包含3个字段,分别是string, int16, int32,成员顺序对内存占用的影响。
|
|
每个字段按照自身的对齐倍数来确定在内存中的偏移量,所以字段排列顺序不同,上一个字段因偏移而浪费的大小也不同。
先看s1:
- a是第一个字段,默认对齐,占用16个字节;
- b是第二个字段,对齐倍数为2,因为当前内存已经是对齐的,只接占用2个字节;
- c是第三个字段,对齐倍数为4,必须空出2个字节,才能对齐4字节;
16 + 2 + 2(被浪费的) + 4 = 24
因此,s1共占用24个字节。
再看s2:
- b是第一个字段,默认对齐,占用2个字节;
- a是第二个字段,对齐倍数为16,必须空出6个字节,才能对齐,直接占用16个字节
- c是第三个字段,对齐倍数为4,因为当前内存已经是对齐的,直接占用4个字节,后4个字节造成浪费
2+6(被浪费的)+16+4+4(被浪费的) = 32
因此,s2共占用32个字节。
技巧:通常将字段内存大小按照从大到小的顺序来排列,可以保证整个结构体所占内存最小。
3.2 空struct{}的处理
空struct{}
大小为0,不占用内存。但是当空struct{}
作为其他结构体的最后一个字段时,需要内存对齐。如果有指针指向该字段,返回的地址将在结构体外,那么当指针一直存活不释放时,就会造成内存泄漏,即该内存不随结构体的释放而释放。
举个例子:
|
|
s3为8个字节,即空struct{}
填充了4个字节;s4为4个字节,空struct{}
不占用内存。
- 原文作者:Kevin
- 原文链接:http://www.subond.com/post/2022-09-07_golang_struct_memory_alignment/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。