对象内存的影响因素

519 阅读4分钟

前言

通过前文对alloc流程的探索,已经清楚了alloc方法的调用流程,但是创建对象应该开辟多大的内存空间依然是个疑问,带着这样的疑问,开始下面的探索

1.首先创建一个XQPerson类,不声明任何属性和方法

image.png

2.只声明属性

image.png

3.只声明成员变量

image.png

4.只声明方法

image.png

5.声明成员变量和方法

image.png

结论: 1.未声明任何属性和方法时,类的实力对象的内存大小为 isa 指针8字节,添加成员变量或属性后实例对象内存isa指针的8字节加上各成员变量所占字节数之和然后以8字节对齐。

2.只有成员变量会影响对象的内存空间,方法不会对对象内存空间有任何影响(实例方法在类的method_list,类方法在元类的method_list

字节对齐

1.8字节对齐 上文提到,对象所占内存空间为8字节对齐,我们找到对象内存8字节对齐的代码如下:

image.png

(x + WORD_MASK) & ~WORD_MASKx是参数,类型是size_t,代表当前对象声明各成员变量的字节数之和unalignedInstanceSizeWORD_MASK是宏定义,64位系统下值是7,假设x = 20,那么表达式就是:

(20 + 7 & ~7
 = 0001 0100 + 0000 0111 & 1111 1000
 = 0001 1011 & 1111 1000
 = 0001 1000 = 24

2.16字节对齐

image.png

(x + size_t(15)) & ~size_t(15)x是参数,类型是size_t,代表当前对象声明各成员变量字节数之和进行8字节对齐的值,假设x = 24那么表达式就是:

(24 + 15 & ~15
 = 0001 1000 + 0000 1111 & 1111 0000
 = 0010 0111 & 1111 0000
 = 0010 0000 = 32

内存对齐的原因: 如下一个类的对象,isa占用8个字节,各成员变量分别占用8,1,4个字节,一共占据21个字节,如果按照图一方式读取数据,需要多次更换读取字节长度,

@interface XQPerson : NSObject
@property(nonatomic,copy)NSString* name;
@property(nonatomic,assign)char sex;
@property(nonatomic,assign)int height;
@end

未命名.gif

结构体内存对齐

内存对齐原则:

  • 数据成员对齐规则:结构体(struct)或联合体(union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的存储位置要从该成员大小或成员的子成员大小(只要该成员有子成员,比如说是数组结构体等)的整数倍开始(比如int是4字节,则要从4的整数倍地址开始存储)。

  • 结构体作为成员,如果一个结构体里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储(struct a里面有struct b,b里面有char,int,double等元素,那b应该从8的整数倍开始存储)。

  • 收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员大小的整数倍,不足的要补齐。

image.png

对象内存对齐

我们知道,对象的成员是8字节对齐,那么对象与对象之间是也是8字节对齐吗?

通过下面的打印可知,对象与对象之间是16进制对齐

image.png

系统在什么时候进行的16进制对齐呢?

image.png

image.png

通过源码跟流程可以找到,在 instanceSize方法中,当有缓存size时进行16字节对齐。

但是当没有缓存,会怎么进行16字节对齐呢?

image.png

我们通过注释return cache.fastInstanceSize(extraBytes);执行后续代码,发现返回的size为 isa 与各成员变量字节数相加后8进制对齐,那么此时使用 size 为24执行 calloc后对象是8字节对齐还是16进制对齐呢?

image.png

通过上面的打印,发现,此时对象仍然是16字节对齐。那么此时是在什么时候进行的16字节对齐呢?

跳转进入 calloc方法,发现此方法源码在malloc

image.png

我们找到libmalloc源码

image.png

执行 calloc(1,24)通过跟流程,找到16进制对齐方法如下

image.png

image.png

执行完 calloc函数后,打印结果如下: image.png

malloc流程图:

Untitled Diagram.drawio (2).png

总结:

  • 只有成员变量会影响对象的内存
  • 对象的成员变量,8字节对齐,相加不满8字节的优化放在一起,不足的补0。
  • 对象与对象,16字节对齐。