iOS alloc 流程分析

作者: differ_iOSER | 来源:发表于2020-09-05 21:55 被阅读0次

    iOS 底层探索 文章汇总

    一、思考

    1. alloc 到底做了什么事?
    2. init 有什么用?
    3. [[Class alloc] init] 与 new有什么区别?
    WX20200905-111912.png

    通过这段代码,我们可以看出p1、p2、p3的指针地址虽然不同,但是指向的对象却是同一个,也就是同一片内存空间。

    + (instancetype)alloc OBJC_SWIFT_UNAVAILABLE("use object initializers instead");
    

    二、alloc源码分析

    准备工作

    1.从 苹果官方开源代码列表 找到 objc4源码,但是这个源码是不可以编译的,需要编译的源码可在这里下载、配置源码可编译调试可参考这里

    2.进入alloc方法可看到:

    + (id)alloc {
        return _objc_rootAlloc(self);
    }
    

    3.跟踪代码,调用方法如下:


    方法调用.png

    4.具体分析_class_createInstanceFromZone方法


    _class_createInstanceFromZone.png

    5.因此,我们就可以确定alloc至少做了两件事:\color{red}{开辟内存、初始化isa指针并关联类}

    6.没属性的对象为什么会占用内存?
    每个对象都有一个隐藏属性isa 每个指针占8个字节---目前系统分配空间是以16字节为单位,通过字节对齐。一个对象只有isa指针也会占16个字节

    具体的内存对齐原则的相关描述可以查看:iOS内存对齐原则
    需要注意的是目前采用的是16字节对齐

    三、既然alloc将开辟内存关联类型都做了,那么init又是在干嘛呢?

    1.定位代码:

    - (id)init {
        return _objc_rootInit(self);
    }
    
    _objc_rootInit(id obj)
    {
        // In practice, it will be hard to rely on this function.
        // Many classes do not properly chain -init calls.
        return obj;
    }
    
    1. \color{red}{可见init仅仅只是将alloc开辟的对象直接返回了,是一种工厂化的设计,方便我们对类进行重写。}

    四、那么new 与[[Class alloc] init] 有什么区别呢?

    1.定位代码

    + (id)new {
        return [callAlloc(self, false/*checkNil*/) init];
    }
    
    callAlloc(Class cls, bool checkNil, bool allocWithZone=false)  //new 使用默认参数
    {
    #if __OBJC2__
        if (slowpath(checkNil && !cls)) return nil;
        if (fastpath(!cls->ISA()->hasCustomAWZ())) {
            return _objc_rootAllocWithZone(cls, nil);
        }
    #endif
    
        // No shortcuts available.
        if (allocWithZone) {
            return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);
        }
        return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc));
    }
    
    
    // Base class implementation of +alloc. cls is not nil.
    // Calls [cls allocWithZone:nil].
    id
    _objc_rootAlloc(Class cls)
    {
        return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);//alloc的参数allocWithZone为true
    }
    

    2.可见new和[[Class alloc] init],唯一区别就是allocWithZone参数为false
    iOS 中 alloc init 和new的区别


    扩展一、fastpath 和 slowpath

    #define fastpath(x) (__builtin_expect(bool(x), 1))
    
    #define slowpath(x) (__builtin_expect(bool(x), 0))
    

    __builtin_expect(exp, n) 方法表示 exp 很有可能为 0,返回值为 exp。
    fastpath意思是:bool(x)为真的概率很大
    slowpath意思是: bool(x)为真的概率很小

    首先要明确:

    if(fastpath(value))  //等价于 if(value)
    if(slowpath(value))  //也等价于 if(value)
    

    也就是说,使用fastpath(),执行 if 后面的语句的机会更大,使用 slowpath(),执行 else 后面的语句的机会更大。通过这种方式,编译器在编译过程中,会将可能性更大的代码紧跟着起面的代码,从而减少指令跳转带来的性能上的下降。

    其实将fastpath和slowpath去掉是完全不影响任何功能的。之所以将fastpath和slowpath 放到if语句中,是为了告诉编译器,if中的条件是大概率(fastpath)还是小概率(slowpath)事件,从而让编译器对代码进行优化。参考

    扩展二、[[NSObject alloc] init]和[[LGPerson alloc] init]差异

    NSObject *objc1 = [[NSObject alloc] init];
    方法调用如下:

    // Calls [[cls alloc] init].
    id
    objc_alloc_init(Class cls)
    {
        return [callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/) init];
    }
    

    LGPerson *objc2 = [[LGPerson alloc] init];
    方法调用如下:

    // Calls [[cls alloc] init].
    id
    objc_alloc_init(Class cls)
    {
        return [callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/) init];
    }
    
    
    + (id)alloc {
        return _objc_rootAlloc(self);
    }
    
    
    // Base class implementation of +alloc. cls is not nil.
    // Calls [cls allocWithZone:nil].
    id
    _objc_rootAlloc(Class cls)
    {
        return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
    }
    
    然后调用
    - (id)init {
        return _objc_rootInit(self);
    }
    

    流程图如下:

    WX20200905-215003.png

    具体流程图如下:


    1616482-20d480c0d97b38b9.png

    流程图参考:陪妮走未来

    文章参考一:NSObject +alloc做了什么
    文章参考二:OC踩坑第一篇:alloc流程初探

    相关文章

      网友评论

        本文标题:iOS alloc 流程分析

        本文链接:https://www.haomeiwen.com/subject/qpwxektx.html