底层原理-01-alloc流程

393 阅读3分钟
  • 从今天开始记录下自己学习的一些心得----开始的日子 oc中,万物皆可对象,对于对象初始化方式一般来说就是 [[class alloc]init][claas new] 或者开发者自定义的一些初始化方法比如:[[class alloc]initWithFrame:()]等,关于他们的区别今天暂时不说,网上也有很多资料。今天主要想讲的 alloc的流程,到底是怎么样实现的。

1.alloc&init

截屏2021-06-05 上午11.18.51.png 我们可以发现p1,p2,p3相同,说明alloc后对象内存确定后,在进行init 的时候改变的是指向该对象的指针地址发生改变

2.三种探寻底层代码流程的方式

2.1符号断点

当法处打断点后,control + step into 进入 找到方法,添加符号断点进行分析

截屏2021-06-08 上午7.06.54.png

截屏2021-06-08 上午7.12.33.png

截屏2021-06-08 上午7.18.11.png

截屏2021-06-08 上午7.18.40.png

2.2汇编

断点打在想要知道的地方,Xcode -> Debug -> Debug Workflow -> Always Show Disassembly 进入汇编找到跳转的方法

截屏2021-06-08 上午7.25.12.png 此时有两种选择方式,你可以继续control step into不断的进入查看流程,但是中间比较繁琐有可能。 截屏2021-06-08 上午7.26.41.png 你也可以通过上面的符号断点找到关键的方法进行分析

2.3符号断点,断住位置

我们开发中,可以根据我们探究的方法直接添加符号断点,比如alloc的探究,我们直接给alloc添加符号断点

截屏2021-06-08 上午7.42.03.png 但是值得注意的是可能会有其他类调用该方法,我们可以运行的时候跳过,走到我们关注的方法的时候在打开

截屏2021-06-08 上午7.44.09.png

截屏2021-06-08 上午7.47.53.png 3. 源码分析 我们通过下符号断点的形式看alloc方法,由于只能看到.h文件,没办法看到.mm的具体实现,这个时候就需要我们定位objec源码。 进入后发现首先会调用alloc方法会调用_objc_rootAlloc 但是实际情况llvm会进行封装alloc 方法变为objc_alloc

截屏2021-06-05 下午5.22.01.png 之后继续跟发现_objc_rootAlloc 会调用callAlloc

截屏2021-06-05 下午5.24.07.png 这个时候发现alloc的核心是callAlloc

截屏2021-06-05 下午5.26.42.png 发现如果是objc2 进入首先检查这个类没有的话直接返回nil; 进入fastpath如果这个必然存在的类的指针对象有默认的 alloc/allocwithzone方法后进入_objc_rootAllocWithZone之后继续进入会调用_class_createInstanceFromZone

截屏2021-06-05 下午5.57.49.png 首先我们先要计算出这个开辟所需的空间大小 size = cls->instanceSize(extraBytes); 如果知道要分配的内存空间的大小的话,调用malloc返回一个对象,不是的话调用calloc返回的是一个数组申请开辟一个内存,返回地址指针 然后判断obj是否存在,不存在的话就返回一个badAcllocHandler或者nil 之后进行初始化isa指针对象 obj->initInstanceIsa(cls, hasCxxDtor);关联相连的类

3.init&& new

- (id)init {
    return _objc_rootInit(self);
}
+ (id)new {
    return [callAlloc(self, false/*checkNil*/) init];
}

init实例方法 返回一个实例化自己,方便我们转换其它类型new就是 alloc 方法和init合并了。

整体的流程图大概如下

alloc流程.jpg 如有错误,请大家多多包涵。