引言
上一篇文章,探究 alloc
的过程中,提到内存对齐
。下面我们通过对OC对象QLPerson
探究来展开内存对齐的探究。
OC对象本质
我们探究oc对象底层的本质,通过如下方式,讲.m
文件转为.cpp
文件。参考我的这篇文章
QLPerson.h
代码如下:
QLPerson.m
如下:image.png
我通过
xcrun
来转成cpp
文件
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc QLPerson.m -o QLPerson.cpp
将QLPerson.cpp
拖入xcode,compile sources去掉QLPerson.cpp
,使其不参与编译。在QLPerson.cpp
中搜索QLPerson_
找到底层实现为结构体QLPerson_IMPL
:
其中结构体
NSObject_IMPL
为
struct NSObject_IMPL {
Class isa;
};
由此可得出OC对象的本质是结构体,引出我今天将要探究的结构体内存对齐
结构体内存对齐探究:普通成员变量
定义结构体代码如下:
struct QLStruct1 {
double a; // 8
char b; // 1
int c; // 4
short d; // 2
} struct1;
其中每个成员变量后面的注释为类型所占字节大小
那么struct1的内存到底占多少呢?我们这里用sizeof()
来计算结果:
NSLog(@"%lu",sizeof(struct1));
打印结果如下:
image.png
这24字节是怎么得到的?
首先,我们要了解,结构体对齐有如下原则:
1、数据成员对齐规则:结构(struct)或union的数据成员,第一个数据的成员,放在offset为0 的地方,以后每个数据成员存储的起始位置,要从该成员大小成员的子成员大小(只要该成员有子成员,数组、结构体等)的整数倍开始。
2、结构体作为成员:如果一个结构里,有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。
3、结构体的总大小,也就是sizeOf的结果,必须是其内部成员的整数倍,不足的要补齐
根据内存对齐原则,得到下图是struct1的成员变量的分布情况(excel画的)
image.png
代码如下:
struct QLStruct1 {
double a; // 8 0 1 2 3 4 5 6 7
char b; // 1 8
int c; // 4 (9,10,11) 12 13 14 15
short d; // 2 16 17
} struct1; // 总计:成员变量总和为17,收尾--最大成员变量double(8)的倍数 --> 24
小括号为跳过
9,10,11
为什么会空出来,因为struct1的最大成员变量为double
,也就是最大成员变量的大小为8字节
,根据原则1
,可知该结构体按8字节对齐。char b
排到8
后,int c本应该从9
开始排,但是9
不能被8整除,因此往后移到12
开始分配4字节
给int c
short d
排布结束后,到了17
,根据原则3
,struct1
按照8字节
内存对齐,不足的需要补齐,因此,最终sizeof(struct1)
得到的是24
而不是17
。
结构体内存对齐探究:结构体作为成员变量
struct QLStruct3 {
double a; // 8 0-7
int b; // 4 8 9 10 11
char c; // 1 12
short d; // 2 (13)14 15
int e; // 4 16 17 18 19
struct QLStruct1 stru; // 17 (20,21,22,23)24 25 26 27 ... 40
} struct3; // 总计:成员变量总和为40,收尾--最大成员变量double(8)的倍数 --> 48
小括号为跳过
根据探究普通成员变量的方式,根据原则2
得到sizeof(struct3)
的大小为48
总结
结构体内存对齐,要熟记以上3个原则,则面对复杂的结构体,也能得心应手的处理了。
网友评论