GO内存对齐
go 刘宇帅 4年前 阅读量: 1463
内存对齐的作用
- 平台原因(移植):不是所有的硬件平台都可以访问任意位置上的任意数据的,有些硬件只能在特定位置取特定数据。
- 性能问题:经过内存对齐,CPU的内存访问速度会提升。因为对齐的元素只需要一次内存访问,未对齐的需要两次。
性能问题
一般程序员会认为内存如下图所示,是有一个个的字节组成,而CPU却不是这样看待的。
CPU把内存当作一块一块的,块的大小可以是2、4、8、16字节大小,因此CPU读取内存是一块一块读取的。(块的大小称为内存读取粒度)
假设CPU要读取一个int型4字节大小的数据,分两种情况讨论:
- 数据从0字节开始
- 数据从1字节开始 假设内存读取粒度为4:
当数据从0字节开始时,CPU只需要读取一次内存即可取到数据。
当数据从1字节开始时,CPU读取数据就变得复杂了,因为数据没有在一个块内存储。这种情况下,CPU先访问内存读取0-3字节数据,在访问内存读取4-7字节数据,然后把0、5、6、7字节的数据去掉,合并1、2、3、4字节数据。这样的操作显然是浪费了很多性能,所以就有了字节对齐,以空间换时间。
内存对齐规则
默认对齐长度:编译器会有一个默认对齐长度,golang 中 64 为系统默认的对齐长度是 8 (这个默认值规则具体不清楚,后面再来补充)
- 对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的起始位置必须是默认对齐长度和该数据成员长度中最小的长度的倍数。
- 除了结构成员需要对齐,结构本身也需要对齐,结构的长度必须是编译器默认的对齐长度和成员中最长类型中最小的数据大小的倍数对齐。
GO类型对齐
package main import ( "fmt" "reflect" ) type Data struct { b byte a int32 x int64 } type Data1 struct { b byte x int64 a int32 } func main() { var d Data t := reflect.TypeOf(d) fmt.Println(t.Size(),t.Align()) var d1 Data t1 := reflect.TypeOf(d1) fmt.Println(t1.Size(),t1.Align()) } ---------- 输出结果: 16 8 24 8
上面的内存结构如下所示:
d 的内存结构: b---|aaaa|xxxx|xxxx
d1的内存结构: b---|----|xxxx|xxxx|aaaa|----
## C 语言
C 语言对齐规则和 golang 一致,C 语言的默认对齐大小由编译器决定,我们也可以通过以下代码修改默认对齐大小。
pragma pack(2) // 修改默认对齐大小为 2