本文主要探索alloc
的底层实现原理:
源码下载
- 大家可以通过 Apple source 在 路径自行下载
objc4-781
源码,但是通过官网下载的源码有报错问题,有时间的小伙伴可以参考iOS-底层原理 03:objc4-781 源码编译 & 调试 - 简书进行修改报错。 - 同时给大家准备好了修改好的源码:GitHub - chenjialin1016/objc4-debugTest: objc4 源码调试 & 源码解读,笔者使用的是objc4-818.2中的KCObjectBuild进行编译 非常值得一读
我们在代码全局中搜索 alloc { 即可找到alloc的底层代码的实现方法,打断点,然后进入方法体,可以判断出方法的进入顺序依次为
注:是因为编译器优化faster,
callAlloc
不一定走.
发现最终进入方法实现体
1、alloc实现的机制主要有以上三步:
cls->instanceSize
计算内存大小calloc
开辟内存方式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
为内存(具体的数据)