对齐原因
- 平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。如基于 Alpha,IA-64,MIPS,和 SuperH 体系的... 拒绝读取未对齐数据。当一个程序要求这些 CPU 读取未对齐数据时,这时 CPU 会进入异常处理状态并且通知程序不能继续执行。所以,如果编译器不进行内存对齐,那在很多平台的上的开发将难以进行。
- 性能原因:经过内存对齐后,CPU的内存访问速度大大提升。CPU 并不是以字节为单位存取数据的,它把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的,每次内存存取都会产生一个固定的开销,减少内存存取次数将提升程序的性能,块大小成为memory access granularity(粒度)“内存读取粒度”。
内存对齐规则
1.数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第
一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置(#pragma pack(指定的数n)要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,
结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存
储,不够整数倍的补齐。
2.结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从
其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b
里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
3.收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。
举例
**
struct DRStruct1 {
double a;
char b;
int c;
char d;
}MyStruct;
sizeof(MyStruct) = 24
struct DRStruct2 {
char d;
char b;
int c;
double a;
}MyStruct1;
sizeof(MyStruct1) = 16
如上所示:结构体中只是将两个元素互换位置,结果所对应的size就不同,故此得出相同的变量,不同声明顺序就会导致结构体大小的不同。
解析
MyStruct.png
-
MyStruct
-
a占用8个字节,起始位置为0,故此a所占位置为(0-7)
-
b占用1个字节,起始位置为8,根据内存对齐规则第一条,起始位置为所占空间的整数倍,可以直接后延,故此b所占位置为(8)
-
c占用4个字节,起始位置为9,而9并非4的整数倍,所以需要后移查找4的整数倍位置,最小为12,因此从12开始后延,位置为(12-15)
-
d占用1个字节,起始位置为16,符合对齐规则,直接后延,占用位置为16
-
综上可得出MyStruct的中占用大小为17根据对齐规则第三条,占用大小应为最大长度成员变量的整数倍,上面成员最大为8,因此应为8的整数倍,最小为24,故此MyStruct的sizeof为24
-
MyStruct1.png
-
MyStruct1
- d占用1个字节,起始位置为0,故此d所占位置为(0)
- b占用1个字节,起始位置为1,符合内存对齐规则,可以直接后延,故此b所占位置为(1)
- c占用4个字节,起始位置为2,而2并非4的整数倍,所以需要后移查找4的整数倍位置,最小为4,因此从4开始后延,位置为(4-7)
- a占用8个字节,起始位置为8,符合对齐规则,直接后延,占用位置为(8 - 15)
- 综上可得出MyStruct的中占用大小为16,符合对齐规则第三条,故此MyStruct的sizeof为16
结构体嵌套结构体
**
typedef struct DRStruct1 {
char b;
double c;
char d;
}MyStruct;
sizeof(MyStruct) = 24
struct DRStruct2 {
char d;
char b;
MyStruct c;
}MyStruct1;
sizeof(MyStruct1) = 32
如上所示,结构体嵌套结构体时,并不是直接返回结构体大小的整数,而是查找结构体中子元素的最大长度的变量,上述代码中MyStruct中最大长度为c,对应的是8个字节,故此最终大小为8的整数倍。
解析
MyStruct1.png
-
MyStruct1
- 由上面的解析可以得出MyStruct为24
- DRStruct2中d占用1个字节,起始位置为0,占用位置为0
- b占用1个字节,起始位置为1,占用位置为1
- MyStruct占用24字节,起始位置为2,根据对其规则,其中最大的为double类型8个字节,故后延查找8的整数倍为8,由此得出从起始位置为8,占用位置为(8-31),共占用31个字节,为8的整数倍,符合对齐规则,得出MyStruct1的sizeof为32.
总结
排放过程中:
1.后面为数据成员,起点为该数据成员的占用字节大小的整数倍; 2.后面为结构体时,起点为结构体中最大元素大小的整数倍地址开始存储;
首尾对齐:
1.结构体中不管有/无嵌套结构体,补齐以所有元素中最大元素大小的整数倍对齐;