iOS 底层原理探索 之 结构体内存对齐
写在前面: iOS底层原理探究是本人在平时的开发和学习中不断积累的一段进阶之
路的。 记录我的不断探索之旅,希望能有帮助到各位读者朋友。
目录如下:
以上内容的总结专栏
准备
Objective-C ,通常写作ObjC或OC,是扩充C的面向对象编程语言。它主要适用于Mac OS X 和 GNUstep者两个使用OpenStep标准的系统,而在NeXTSTEP和OpenStep中它更是基本语言。
GCC和Clang含Objective-C的编译器,Objective-C可以在GCC以及Clang运作的系统上编译。
我们平时开发用的Objective-C语言,编译后最终会转化成C/C++语言。
为什么要研究结构体的内存对齐呢? 因为作为一名iOS开发人员,随着对于底层的不断深入探究,我们都知道,所有的对象在底层中都是一个结构体。那么结构体的内存空间又会被系统分配多少空间,这个问题,值得我们一探究竟。
首先,从大神Cooci那里盗取了一张各数据类型占用的空间大小图片,作为今天探究结构体内存对齐原理的依据。
当我们创建一个对象的时候,我们并不需要过多的在意属性的顺序,因为系统会帮我们做优化处理。但是,在创建结构体的时候,就需要我们去分析了,因为这个时候系统并不会帮助我们做优化。
接下来,我们看下面两个结构体:
struct Struct1 {
double a;
char b;
int c;
short d;
char e;
}struct1;
struct Struct2 {
double a;
int b;
char c;
short d;
char e;
}struct2;
两个结构体拥有的数据类型是相同的,按照图片中double 是8字节, char 是1字节, int 是4字节,short 是2字节, 那么 两个结构体应该是占 16字节的内存空间,也就是分配16字节空间即可,然而,我们看下面的结果:
printf("%lu--%lu", sizeof(struct1), sizeof(struct2));
------------
24--16
那么,这就是有问题的了,两个拥有相同数据类型的结构体,被系统分配到的内存空间是不一样的,这是为什么呢?今天的重点就是这里,结构体的
内存对齐原则:
1:数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第
一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置
要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是
数组,结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址
开始存储。
2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从
其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,
b里有char,int ,double等元素,那b应该从8的整数倍开始存储)
3:收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员
的整数倍,不足的要补⻬。
那么,我们按照以上内存对齐原则再来分析下 struct1 和 struct2 :
struct Struct1 { /// 18 --> 24
double a; //8 [0 1 2 3 4 5 6 7]
char b; //1 [8 ]
int c; //4 [9 [12 13 14 15]
short d; //2 [16 17]
char e; //1 [18]
}struct1;
struct Struct2 { /// 16 --> 16
double a; //8 [0 1 2 3 4 5 6 7]
int b; //4 [8 9 10 11]
char c; //1 [ 12 ]
short d; //2 [14 15]
char e; // 1 [16]
}struct2;
接着,我们看下下面的结构体
struct Struct3 {
double a;
int b;
char c;
short d;
int e;
struct Struct1 str;
}struct3;
打印输出结果为 48
,分析如下:
double a; //8 [0 1 2 3 4 5 6 7]
int b; //4 [8 9 10 11]
char c; //1 [12]
short d; //2 [ 14 15 ]
int e; //4 [ 16 17 18 19]
struct Struct1 str; //24 [24 ... 47]
所以,struct3
大小为48。
猜想:内存对齐的收尾工作中的内部最大成员指的是什么的大小呢?
接下来我们来一一验证一下
struct LGStruct4 { /// 40 --> 48
double a; //8 [0 1 2 3 4 5 6 7]
int b; //4 [8 9 10 11]
char c; //1 [12]
short d; //2 [14 15]
int e; //4 [16 17 18 19]
struct Struct2 str; //16 [24 ... 39]
}struct4;
按照我对于内存对齐原则中收尾工作的理解, 最终的大小 应该是 Struct2
的 大小 16 的整数倍 也就是 48
才对。然而, 结果却是:
NSLog(@"%lu", sizeof(struct4));
--------
SMObjcBuild[8076:213800] 40
对,是40
你没有看错,这样的话,很显然,我理解的就是错误的, 结构体内部最大成员应该指的是这里的 double,那么我们接下来验证一下: 1、
struct Struct2 { ///16
double a; //8 [0 1 2 3 4 5 6 7]
int b; //4 [8 9 10 11]
char c; //1 [ 12 ]
short d; //2 [14 15]
}struct2;
struct LGStruct4 { /// 24
short d; //2 [0 1]
struct Struct2 str; // 16 [8 ... 23]
}struct4;
结果是 :24
因为,结构体内部最大成员是 double
也就是8;并不是按照 LGStruct4
中的str
长度为16的整数倍来计算,所以最后的结果是24。
总结
结构体内部最大成员指的是结构体内部的数据类型
,所以,结构体内包含结构体的时候,并不是按照内部的结构体长度的整数倍来计算的哦。