OC底层原理(一).alloc实际调用流程分析

OC底层原理汇总

在以前分析源码时,都是在OpenSource直接下载,然后全局搜索分析源码调用,在最新的objc781源码下载后,我们进行了可编译调试配置,调试步骤可以参考月神的:objc4-781 源码编译 & 调试

alloc源码调用流程

最新的alloc调用从源码上看和以前的差不多

alloc流程

现在我们使用可调式源码来分析下这个流程是否正确。
我们在可调试源码中添加一个target,并设置objc依赖,如下所示


目录结构
设置依赖

main.h添加代码如下:


#import 
#import "LWClassTest.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        NSObject *obj1 = [NSObject alloc];
        LWClassTest *obj2 = [LWClassTest alloc];
        
        NSLog(@"Hello, World!");
    }
    return 0;
}

我们在obj1生成处打一个断点,并设置Debug->Debug Workflow->Always Show Disassembly来查看汇编中的调用

汇编调用流程

我们看到,在[NSObject alloc]时,调用的是objc_alloc,而并不是我们以为的_objc_rootAlloc,这和我们之前研究源码的认知好像不一样,这是为什么呢?

为什么调用objc_alloc

  • 首先,我们在main中obj1和obj2行都打上断点,并在源码objc_alloc处打上断点,运行前暂时让这里的断点disable,如下图所示

    objc_alloc中打断点

  • 运行,在main中停下时,让objc_alloc处断点enable,继续运行,我们可以看到停在了objc_alloc处的断点,源码中可以看到,下一步调用的是callAlloc,再在callAlloc中打上断点

    callAlloc中断点

  • 继续运行,我们发现它会走到1714行,调用消息发送,给类对象发送一个alloc消息。

  • 再继续运行,它就会走到我们一开始介绍的alloc执行流程。

走到这里,我们发现,虽然验证了中间要走objc_alloc流程,但是为什么会走我们还是没有解释到。
在以前的经验中,我们知道,如果某个方法,如果没有走到它的方法实现,那么它很可能被hook了,这里也是一样的道理,我们的系统在进行alloc时,会对它进行拦截,这部分我们可以看LLVM源码中的实现。

  • 在llvm源码中搜索objc_alloc


  • 搜索shouldUseRuntimeFunctionForCombinedAllocInit,表示版本控制

  • 搜索tryEmitSpecializedAllocInit,非常著名的特殊消息发送,在这里也没有找到 objc_alloc

  • 继续尝试,开启上帝视角,通过alloc字符串搜索,如果还找不到,还可以通过omf_alloc:找到tryGenerateSpecializedMessageSend,表示尝试生成特殊消息发送

  • 然后在这个case中可以找到调用alloc,转而调用了objc_objc的逻辑,其中的关键代码是EmitObjCAlloc


  • 跳转至EmitObjCAlloc的定义可以看到alloc 的处理是调用了 objc_alloc

    EmitObjCAlloc

  • 由此可以得出 NSObject中的alloc 会走到 objc_alloc,其实这部分是由系统级别的消息处理逻辑,所以NSObject的初始化是由系统完成的,因此也不会走到alloc的源码工程中

alloc实际调用流程

所以,在调用alloc方法时,实际的调用流程为:

alloc实际调用流程

你可能感兴趣的:(OC底层原理(一).alloc实际调用流程分析)