背景
为何需要内存对齐?计算机从内存中读取数据是按照一个固定长度来的,以32位机为例,计算机每次读取内存32位(byte),就是每次读取4个字节(一个字节占8位),以int类型为例,如下图所示:


显然,未对齐时,需要读取两次才能将int a读取完全,而对齐时,只需一次,明显提高了效率。当然,内存对齐是会浪费一些空间的,但是这种空间上的浪费却可以减少读取次数,节省了时间,这就是所谓的以空间换时间。计算机采取这种策略必然有它的道理,况且存储器如今越来越便宜,这一点点空间的浪费根本不算什么。
内存对齐原则
1、数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存储。
2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char int double等元素,那b应该从8的整数倍开始存储。)
3、结构体的总大小,也就是sizeof的结果,必须是其内部最大成员变量的整数倍,不足的要补齐。
请看以下代码:

struct的实际大小是0--17,即18个字节,根据内存对齐原则第一条,以8为倍数补齐,所以是24个字节。
特殊情况:结构体嵌套

struct2的大小是40,why?分析:
1、short a占2字节,地址 0--1;
2、struct1 b占24字节,b的成员中double所占字节最长,为8,按照内存对齐原则第二条,那么struct1 b的首地址应该是8的倍数,从8开始,地址8--31;
3、double c占8字节,从地址32开始,正好32是8的倍数,地址32--39。
0--39,大小正好40。
总结
1、内存对齐是以空间换时间,提高了计算机读取内存的效率。
2、数据成员对齐规则,第一个成员从0开始,后面成员的起始位置是从该成员大小的整数倍位置开始。
3、结构体嵌套情况下,该结构体成员的起始位置,是按照其内部最大成员变量的大小的整数倍位置开始。
附件 - 各种数据结构所占字节大小

网友评论