iOS 底层原理 iOS 进阶之路

OC底层原理五: NSObject的alloc分析

2020-09-12  本文已影响0人  markhetao

OC底层原理 学习大纲

在编译时,发现两个问题:
问题1. NSObjectalloc方法不走常规路
问题2. 自定义类HTTestalloc方法进入callAlloc被调用2次

发现路径:

问题1:NSObjectalloc方法不走常规路

我们在[NSObject alloc]入口和alloc类方法打断点:

图一.png image.png

发现未进入alloc类方法。于是在图一断点时,打开汇编模式

汇编模式.png

发现下一个执行函数是objc_alloc

image.png

于是我们全局搜索objc_alloc函数。在NSObject.mm文件中找到objc_alloc函数,加断点检测。

image.png

发现此时cls刚好是NSObject

NSObject alloc.png

接下来调用callAlloc函数,回归正常对象的alloc流程

image.png

新问题:NSObject是如何忽略alloc,直接调用objc_alloc函数的呢?

这里需要通过llvm源码来探究。 源码1G多,这里我展示一下就行。实际上NSObject是系统自动创建和管理的。

image.png image.png

问题2:自定义类HTTestalloc方法进入callAlloc被调用2次

在探究之前,我们先做个小测试。
我们直接加入callAlloc符号断点,直接启动程序

callAlloc断点 NSArray

我们发现第一个进入cls的是NSArray,我们加设断点

image.png

发现他没有进入_objc_rootAllocWithZone,而是发送alloc的消息。

为什么?

image.png image.png image.png

我们发现,NSArrayalloc最终还是交给了系统allocWithZone去处理。😂

[HTTest alloc]

当我们加入HTTest的断点后,会经历系统的NSArray、 NSThread、NSMutableDictionary、NSSet、NSUUID的初始化,最终进入HTTestalloc方法。
与NSArray不同的是,HTTest的第二次调用是_objc_rootAllocWithZone

image.png

那么,问题还是没有回答,知道第一次是发送了alloc消息给系统。但是为什么会调用第二次?

我们回到llvm源码。

image.png

实例检验

image.png
  • 断点进入的顺序如下:
image.png

可以发现,任何类调用alloc时,并不会先进入Alloc类方法直接执行

  • 系统使用objc_msgSend消息机制发送了alloc消息

  • 消息会先到达llvm层GeneratePossiblySpecializedMessageSend函数,条件判断中触发tryGenerateSpecializedMessageSend函数

  • tryGenerateSpecializedMessageSend函数内部将alloc消息转发成了objc_alloc消息。所以我们第一次响应是objc_alloc->callAlloc

  • 第一次时,类没有实现,所以tryGenerateSpecializedMessageSend返回falseif条件不成立,发送GenerateMessageSend常规方法,调用alloc类方法创建。

  • 此时会调用常规的alloc->_objc_rootAlloc->callAlloc流程。

拓展:

  • 当一个创建完第一个实例,再次创建第二个实例时,tryGenerateSpecializedMessageSend会返回true。我们只会响应第一次。不会调用常规的alloc方法哦。 这是缓存的作用。后面熟悉cacheobjc_msgSend机制后,相信你就懂了。
    如:
HTTest * test1  = [HTTest alloc];
HTTest * test2  = [HTTest alloc];

总结

下一节,OC底层原理六: 内存对齐

上一篇 下一篇

猜你喜欢

热点阅读