目录
一、内存对齐原因
我们知道内存的最小单元是一个字节,当cpu从内存中读取数据的时候,是一个一个字节读取,所以内存对我们应该是入下图这样:
但是实际上cpu将内存当成多个块,每次从内存中读取一个块,这个块的大小可能是2、4、8、16等。
那么下面,我们来分析下非内存对齐和内存对齐的优缺点在哪?
内存对齐是操作系统为了提高访问内存的策略。操作系统在访问内存的时候,每次读取一定长度(这个长度是操作系统默认的对齐数,或者默认对齐数的整数倍)。如果没有对齐,为了访问一个变量可能产生二次访问。
- 至此大家应该能够简单明白,为什么要简单内存对齐?
|
二、如何内存对齐
- 对于标准数据类型,它的地址只要是它的长度的整数倍。
- 对于非标准数据类型,比如结构体,要遵循一下对齐原则:
1. 数组成员对齐规则。第一个数组成员应该放在offset为0的地方,以后每个数组成员应该放在offset: min(当前成员的大小,#pargama pack(n))整数倍的地方开始,win#pargama pack(n)默认为8 (比如int在32位机器为4字节,#pargama pack(2),那么从2的倍数地方开始存储)。
2. 结构体总的大小,也就是sizeof的结果,必须是min(结构体内部最大成员,#pargama pack(n))的整数倍,不足要补齐。
3. 结构体做为成员的对齐规则。如果一个结构体B里嵌套另一个结构体A,还是以最大成员类型的大小对齐: min{ 结构体A的起点为A内部最大成员,#pargama pack(n) } (struct B里存有struct A,A里有char,int,double等成员,那A应该从8的整数倍开始存储。),结构体A中的成员的对齐规则仍满足原则1、原则2。 |
手动设置对齐模数:
显示当前packing alignment的字节数,以warning message的形式被显示。
将当前指定的packing alignment数组进行压栈操作,这里的栈是the internal compiler stack,同事设置当前的packing alignment为n;如果n没有指定,则将当前的packing alignment数组压栈。
从internal compiler stack中删除最顶端的reaord; 如果没有指定n,则当前栈顶record即为新的packing alignement数值;如果指定了n,则n成为新的packing alignment值
指定packing的数值,以字节为单位,,合法的数值分别是1,2,4,8,16。 |
Linux 默认#pragma pack(4)
window 默认#pragma pack(8)
内存对齐总结:
第一个属性开始 从0开始计算偏移量。
第二个和之后属性要放在 该属性的大小 与 对齐模数比 取小的值的 整数倍上。
当所有属性都计算完毕后,整体做二次偏移,
将上面计算的结果 扩充到 这个结构体中最大数据类型 与对齐模数 比 取小的值 的整数倍。
三、内存对齐案例
所以案例均是 WIN 64位机上运行。
3.1 对齐模数:8
#pragma pack(8)
typedef struct _STUDENT{ |