什么是内存对齐
计算机中内存的地址空间是按照 byte 来划分的,从理论上讲对任何类型变量的访问可以从内存中的任意地址开始,但实际情况是:在访问特定类型变量的时候通常在特定的内存地址访问,这就需要对这些数据在内存中存放的位置进行限制,各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。编译器将程序中的每个 数据单元 的地址安排在机器字的整数倍的地址指向的内存之中。
为什么要进行内存对齐
主要是由于 CPU 的访问内存的特性决定,CPU 访问内存时并不是以字节为单位来读取内存,而是以机器字长为单位,实际机器字长由 CPU 数据总线宽度决定的。实际 CPU 运行时,每一次控制内存读写信号发生时,CPU 可以从内存中读取数据总线宽度的数据,并将其写入到 CPU 的通用寄存器中。比如 32 位 CPU,机器字长为 4 字节,数据总线宽度为 32 位,如果该 CPU 的地址总线宽度也是为 32 位,则其可以访问的地址空间为 [0,0xffffffff]。内存对齐的主要目的是为了减少 CPU 访问内存的次数,加大 CPU 访问内存的吞吐量。假设读取 8 个字节的数据,按照每次读取 4 个字节的速度,则 8 个字节需要 CPU 耗费 2 次读取操作。CPU 始终以字长访问内存,如果不进行内存对齐,很可能增加 CPU 访问内存的次数。
比如以上在读取变量 b 时,如果不进行内存对齐的话,会导致 CPU 读取次数为 2,在内存对齐的情况下,只需读取一次即可。首先,CPU访问按字长访问内存,每次读4个字节(对于32位计算机而言)。如果存储没有对齐,则b需要分两次读,因为b跨在了第一个字长和第二个字长中间
内存对齐的原则
一、结构体对齐规则首先要看有没有用#pragma pack宏声明,这个宏可以改变对齐规则
二、在没有#pragma pack这个宏的声明下,遵循下面三个原则:
- 第一个成员的首地址为0.
- 每个成员的首地址是自身大小的整数倍
- 结构体的总大小,为其成员中所含最大类型的整数倍