iOS-底层原理 02:alloc & init & new 源码分析

61 阅读3分钟

本文主要探索alloc的底层实现原理:

源码下载

我们在代码全局中搜索  alloc {  即可找到alloc的底层代码的实现方法,打断点,然后进入方法体,可以判断出方法的进入顺序依次为

​ 注:是因为编译器优化faster,callAlloc不一定走. image.png

发现最终进入方法实现体

1、alloc实现的机制主要有以上三步:

  1. cls->instanceSize计算内存大小
  2. calloc开辟内存方式
  3. obj->initInstanceIsa isa与类绑定在一起

第一步 :cls->instanceSize

    我们继续进入方法体,进入以下关键方法

​编辑 其中x + size_t(15) = 23,即23的二进制数据与15的取反二进制数据进行位运算,即0000 0000 0001 0000,转换为十进制为16,即NSObject申请了一块16字节的存储区,但是实际上只使用了8字节

0000 0000 0000 1111 = 15
1111 1111 1111 0000 = -15

x+size_t(15) & ~15 相当于后四位抹零,其他位数不变

我们发现计算结果均为16的整数倍,由此得出结论,此算法的目的就是16字节对齐

为什么需要8字节,却要补齐16字节(16字节对齐):

       1. IO比较耗时,系统规定存储区为16字节的整数倍,便于提高效率,不用读取实际数据长度

       2.8字节补齐至16字节,系统每次读取16字节就不会产生野指针,更加安全

第二步 :calloc开辟内存方式

我们看到执行完第二步的时候系统为对象开辟了一段内存空间并返回了指针

第三步 :obj->initInstanceIsa isa与类绑定在一起

执行完第三步我们发现,obj的对象变成了指向0x10060da10的NSObject对象,总结:

相同的方法我们查看init的方法与new的方法如下

​ 以上我们得知,init只是返回了当前的地址,new执行的方法与allocinit一致,那为什么要这样写呢?

        init:方便子类进行重写

2、alloc.init与new的区别:

两种方式创建对象现在基本上一样,区别就是使用new只能默认init进行初始化,alloc方式可以使用其它的init开头的方法进行初始化。

还有一点,在其实默认的init方法中 , 什么都没有做,直接返回了self , 所以,如果没有重写init的话, [Class new][[Class alloc]init] 是等价的.

3、影响对象开辟内存的因素:

        我们生成一个CCCCObject的类来看看对象生成内存的大小

​ 

 size的字节为16,我们分别添加两个属性看看多少字节

添加一个属性为16个字节,两个属性为32个字节

因此属性可以影响对象开辟内存的情况

对对象进行复制

Ox10152c920指针地址0x011d8001000081fd内存(具体的数据)