一、什么是内存对齐
内存对齐是一种在计算机内存中排列数据(表现为变量的地址)、访问数据(表现为CPU读取数据)的一种方式。它包含了两种相互独立又相互关联的部分:基本数据对齐和结构体数据对齐 。
二、为什么要进行内存对齐?
1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
三、内存对齐原则
1、基本数据对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的存储起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存储。
typedef HFStruct1{
char arr[2]; // size: 2 offset:0~1 2 + 2 = 4(因为成员b占用4个字节,b的offset又要从4的整数倍开始,所以4字节补齐)
int b; // size: 4 offset:4~7 4 + 4 = 8(因为b占4个字节,所以要从4的整数倍开始, 所以上面的arr要补齐4字节)
double c; // size: 8 offset:8~15 8 + 8 = 16
}MyStruct1;
根据上面的推算可得出: size 总大小为2+4+8=14; (对齐之后)系统开辟内存应为 16, 接下来打印验证一下
(lldb) po sizeof(MyStruct1)
16
2、结构体对齐规则:结构体的总大小,必须是其内部最大成员占用内存的整数倍.不足的要补⻬
typedef HFStruct2{
char a; // size: 1 offset:0~0 1 + 7 = 8(补齐8字节)
double b; // size: 8 offset:8~15 8 + 8 = 16(因为b占8个字节,所以要从8的整数倍开始, 所以上面的a要补齐8字节)
int c; // size: 4 offset:16~19 16 + 4 = 20
short d; // size: 2 offset:20~21 20 + 2 = 22
}MyStruct2;
根据上面的推算可得出: size 总大小为1+8+4+2=15; (对齐之后)系统开辟内存应为 24 (22+2对齐为8的整数倍), 接下来打印验证一下
(lldb) po sizeof(MyStruct2)
24
打印出来的MyStruct2的大小却是24
3、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
typedef HFStruct3{
char a; // size: 1 offset:0~0 1 + 7 = 8(补齐8字节)
double b; // size: 8 offset:8~15 8 + 8 = 16(因为b占8个字节,所以要从8的整数倍开始, 所以上面的a要补齐8字节)
int c; // size: 4 offset:16~19 16 + 4 = 20(注意:此时下一个成员d中的子成员最大占用8字节, 而20又不是8的倍数,所以要补齐到24)
struct HFStruct2 d; // size: 24 offset:24~47 24+24 = 48
}MyStruct3;
根据上面的推算可得出: size 总大小为1+8+4+24=37; (对齐之后)系统开辟内存应为 48, 接下来打印验证一下
(lldb) po sizeof(MyStruct3)
48
打印出来的MyStruct3的大小为48
网友评论