阅读 58

iOS底层-结构体内存对齐

前言

大家都知道系统对我们平时创建的对象做了内存优化,那么系统是怎么做的呢?这个就涉及到了结构体的内存对齐,接下来我们一起探索吧!

结构体内存对齐的三大原则

原则1:第一个数据成员存储的起始位置从offset为0的位置开始,后面每个数据成员存储的起始位置要从该成员字节大小的整数倍开始。

原则2:如果结构体的数据成员里包含结构体,那么结构体成员存储的起始位置要从其内部最大成员大小的整数倍开始。

原则3:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员大小的整数倍(注释:结构体成员不能当成一个整体看待,实际上是取其子成员最大的大小做为它的大小),不足的要补齐。

实践

如果不清楚某个数据类型所占的内存字节数,可以用sizeof()方法打印
首先我们分析一个数据成员都是基本数据类型的结构体。

40.png 打印一下,验证我们的计算结果。

41.png OK。没问题。到这里有个疑问?为什么要从数据成员字节大小的整数倍开始存储呢?
答案是为了读取效率。用空间换时间。下面画个图解释一下。

17.png 先用1字节读取了1字节大小的内存地址。那么后面4字节的内存地址最开始也用1字节读取,发现读取不到,变为2字节读取,依旧读不到。直到变为4字节时才能读取到。这多浪费时间和性能啊。那么如果换成下面图里的情况是不是会好些呢?

18.png 很显然,这次用4字节大小读取,仅仅2次就可以全部读取成功。这也就解释了为什么要从数据成员字节大小的整数倍开始存储的疑惑了。

下面我们分析一个数据成员包含结构体的结构体。

42.png 打印一下,验证我们的计算结果。

43.png OK。没问题。

最终目的

理解了结构体内存对齐的方式和原因,我们也就大概知道了系统是如何优化对象内存的。那么影响对象内存大小的因素又有哪些呢?(无非就是成员变量和方法嘛)
先创建一个LLPerson类。.h里面没有任何声明。

24.png 此时打印一下LLPerson的内存

25.png 我们添加一个成员变量(属性)再试试

28.png

29.png 发现内存大小发生了变化。加了8。看来成员变量确实可以影响对象的内存大小。
那么我们添加方法试试

30.png

31.png 发现内存大小没有发生变化。还是16.说明方法不可以影响对象的内存大小。

总结:成员变量影响对象的内存大小,方法不影响。
实际上继承自NSObject对象的类,类自身的内存对齐方式是【8】字节对齐。可以理解成系统(至少)要给这个对象开辟的内存大小。
那么系统(实际)给对象开辟了多少内存大小?这里涉及到了malloc函数。实际上系统为对象开辟内存的对齐方式是【16】字节对齐。malloc函数我们后续再研究,就先到这里了。

文章分类
iOS
文章标签