iOS alloc

作者: forping | 来源:发表于2021-02-24 10:18 被阅读0次

    首先介绍几个方法和宏

    static ALWAYS_INLINE uintptr_t 
    subc(uintptr_t lhs, uintptr_t rhs, uintptr_t carryin, uintptr_t *carryout)
    {
        return __builtin_subcl(lhs, rhs, carryin, carryout); // 作用就是前两个参数相减,当不够减的时候carryout是1,当够减的时候carryout为0
    }
    static ALWAYS_INLINE uintptr_t 
    addc(uintptr_t lhs, uintptr_t rhs, uintptr_t carryin, uintptr_t *carryout)
    {
        return __builtin_addcl(lhs, rhs, carryin, carryout); // 作用就是前两个参数相加,当相加之后的值超过了第一个参数类型所能表示的范围就会溢出carryout为1否则为0
    }
    
    #define fastpath(x) (__builtin_expect(bool(x), 1)) // x的值大部分情况下可能为真,这样编译器在编译这段代码时就会将下一个函数紧挨着if条件跳转指令。
    #define slowpath(x) (__builtin_expect(bool(x), 0))// 表示x的值大部分情况下可能为假,因此下一个函数得到执行的机会比较少。这样编译器在编译这段代码时就不会将下一个函数的汇编指令紧挨着if条件跳转指令。
    /*__builtin_开头的符号是一些编译器内置的函数或者编译优化处理开关等,
    作用类似于宏。而内置函数则是用于在编译阶段进行替换的机器指令块。
    因此编译器的这些内置函数其实并不是真实的函数,而只是一段指令块,起到编译时的内联功能*/
    
    内置函数和非内置函数的调用的区别

    alloc

    当我们调用alloc方法时,调用过程如下

    alloc

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

    _objc_rootAlloc

    id
    _objc_rootAlloc(Class cls)
    {
        return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
    }
    

    callAlloc

    static ALWAYS_INLINE id
    callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
    {
    #if __OBJC2__
        if (slowpath(checkNil && !cls)) return nil;
    // 类或父类是否具有默认的alloc / allocWithZone: 存储在元类,如果有就调用alloc / allocWithZone方法,没有就调用_objc_rootAllocWithZone方法
        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));
    }
    
    

    _objc_rootAllocWithZone

    id
    _objc_rootAllocWithZone(Class cls, malloc_zone_t *zone __unused)
    {
        // allocWithZone under __OBJC2__ ignores the zone parameter
        return _class_createInstanceFromZone(cls, 0, nil,
                                             OBJECT_CONSTRUCT_CALL_BADALLOC);
    }
    

    _class_createInstanceFromZone

    static ALWAYS_INLINE id
    _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
                                  int construct_flags = OBJECT_CONSTRUCT_NONE,
                                  bool cxxConstruct = true,
                                  size_t *outAllocatedSize = nil)
    {
        ASSERT(cls->isRealized());
    
        // Read class's info bits all at once for performance
    // 有c++构造函数
        bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
    // 有c++析构函数
        bool hasCxxDtor = cls->hasCxxDtor();
    // 是否可以创建优化过isa的实例对象
        bool fast = cls->canAllocNonpointer();
        size_t size;
    // 需要开辟的内存空间
        size = cls->instanceSize(extraBytes);
        if (outAllocatedSize) *outAllocatedSize = size;
    
        id obj;
    // 开辟内存空间
        if (zone) {
            obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
        } else {
            obj = (id)calloc(1, size);
        }
        if (slowpath(!obj)) {
            if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
                return _objc_callBadAllocHandler(cls);
            }
            return nil;
        }
      // 关联到对应的类
        if (!zone && fast) {
            obj->initInstanceIsa(cls, hasCxxDtor);
        } else {
            // Use raw pointer isa on the assumption that they might be
            // doing something weird with the zone or RR.
            obj->initIsa(cls);
        }
    
        if (fastpath(!hasCxxCtor)) {
            return obj;
        }
    
        construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;
        return object_cxxConstructFromClass(obj, cls, construct_flags);
    }
    

    关联到类 initIsa

    inline void 
    objc_object::initIsa(Class cls, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor)
    { 
        ASSERT(!isTaggedPointer()); 
        
    // 创建isa
        isa_t newisa(0);
        if (!nonpointer) {
            newisa.setClass(cls, this);
        } else {
            ASSERT(!DisableNonpointerIsa);
            ASSERT(!cls->instancesRequireRawIsa());
    
    
    #if SUPPORT_INDEXED_ISA
            ASSERT(cls->classArrayIndex() > 0);
            newisa.bits = ISA_INDEX_MAGIC_VALUE;
            // isa.magic is part of ISA_MAGIC_VALUE
            // isa.nonpointer is part of ISA_MAGIC_VALUE
            newisa.has_cxx_dtor = hasCxxDtor;
            newisa.indexcls = (uintptr_t)cls->classArrayIndex();
    #else
            newisa.bits = ISA_MAGIC_VALUE;
            // isa.magic is part of ISA_MAGIC_VALUE
            // isa.nonpointer is part of ISA_MAGIC_VALUE
    #   if ISA_HAS_CXX_DTOR_BIT
            newisa.has_cxx_dtor = hasCxxDtor;
    #   endif
            newisa.setClass(cls, this);
    #endif
            newisa.extra_rc = 1;
        }
    
        // 绑定isa
        isa = newisa;
    }
    

    但在进行汇编展示的时候.
    创建自定义对象的函数执行顺序: objc_alloc_init ->callAlloc-> alloc ->_objc_rootAlloc -> callAlloc -> _objc_rootAllocWithZone -> _class_createInstanceFromZone , 而NSObject调用顺序是objc_alloc-> callAlloc -> _objc_rootAllocWithZone -> _class_createInstanceFromZone

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

    init

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

    - (id)init {
        return _objc_rootInit(self);
    }
    
    id
    _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;
    }
    

    源码展示,init仅仅是返回了obj

    new

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

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

    仅仅是 callAlloc 函数的第三个参数取的默认值false

    相关文章

      网友评论

          本文标题:iOS alloc

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