美文网首页
OC的对象原理之 alloc流程分析

OC的对象原理之 alloc流程分析

作者: 爱你因为泰勒 | 来源:发表于2020-07-20 11:27 被阅读0次

    alloc

    我们往里一直深究应该是以下的一个流程:

    1.进入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*/);
    }
    
    // Calls [cls alloc].
    id
    objc_alloc(Class cls)
    {
        return callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/);
    }
    
    // Calls [cls allocWithZone:nil].
    id 
    objc_allocWithZone(Class cls)
    {
        return callAlloc(cls, true/*checkNil*/, true/*allocWithZone*/);
    }
    

    callAlloc中有三个参数:cls 类的信息 (Class)/ checkNil 是否需要检查cls为不为nil/ allocWithZone 如果为true,会默认在NSZone自动分配内存

    2.进入callAlloc
    // Call [cls alloc] or [cls allocWithZone:nil], with appropriate 
    // shortcutting optimizations.
    static ALWAYS_INLINE id
    callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
    {
        if (slowpath(checkNil && !cls)) return nil;
    
    #if __OBJC2__
        if (fastpath(!cls->ISA()->hasCustomAWZ())) {
            // No alloc/allocWithZone implementation. Go straight to the allocator.
            // fixme store hasCustomAWZ in the non-meta class and 
            // add it to canAllocFast's summary
            if (fastpath(cls->canAllocFast())) {
                // No ctors, raw isa, etc. Go straight to the metal.
                bool dtor = cls->hasCxxDtor();
                id obj = (id)calloc(1, cls->bits.fastInstanceSize());
                if (slowpath(!obj)) return callBadAllocHandler(cls);
                obj->initInstanceIsa(cls, dtor);
                return obj;
            }
            else {
                // Has ctor or raw isa or something. Use the slower path.
                id obj = class_createInstance(cls, 0);
                if (slowpath(!obj)) return callBadAllocHandler(cls);
                return obj;
            }
        }
    #endif
    
        // No shortcuts available.
        if (allocWithZone) return [cls allocWithZone:nil];
        return [cls alloc];
    }
    

    在这个方法中,先判断hasCustomAWZ(),当前class是否有默认的allocWithZone,没有重写就会越过canAllocFast()(当前默认是false)条件,并且直接调用class_createInstance()_class_createInstanceFromZone()方法来开辟内存空间。

    3.需要开辟的空间大小

    _class_createInstanceFromZone方法中可以看到instanceSize方法,在该方法中可以看到对象开辟的空间大小最少是16字节。

    size_t instanceSize(size_t extraBytes) {
          size_t size = alignedInstanceSize() + extraBytes;
          // CF requires all objects be at least 16 bytes.
          if (size < 16) size = 16;
          return size;
    }
    

    而在alignedInstanceSize方法中,我们可以看到,开辟空间大小的一个原则:内存对齐

    // Class's ivar size rounded up to a pointer-size boundary.
        uint32_t alignedInstanceSize() {
               //内存对齐
            return word_align(unalignedInstanceSize());
        }
    
    static inline uint32_t word_align(uint32_t x) {
        // 7+8 = 15
        // 0000 1111
        // 0000 1000
        //&
        // 1111 1000 ~7
        // 0000 1000 8
        
        // 0000 0111
        //
        // x + 7
        // 8
        // 8 二阶
        // (x + 7) >> 3 << 3
        return (x + WORD_MASK) & ~WORD_MASK;
    }
    static inline size_t word_align(size_t x) {
        return (x + WORD_MASK) & ~WORD_MASK;
    }
    

    一个对象、指针 占用 8字节, 而我们对象所需的内存空间也得是8的倍数,默认规定内存空间必须是大于等于16字节

    在计算需要开辟的内存后,我们需要申请内存、创建对象,初始化isa,并关联类、对象,在_class_createInstanceFromZone方法中,如下:

        id obj;
        if (!zone  &&  fast) {
          //申请内存,创建对象
            obj = (id)calloc(1, size);
            if (!obj) return nil;
            //初始化isa,将内存空间与类、对象关联起来
            obj->initInstanceIsa(cls, hasCxxDtor);
        } 
        else {
            // 申请内存空间,创建对象
            if (zone) {
                obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
            } else {
                obj = (id)calloc(1, size);
            }
            if (!obj) return nil;
    
            // Use raw pointer isa on the assumption that they might be 
            // doing something weird with the zone or RR.
            //初始化isa,将内存空间与类、对象关联起来
            obj->initIsa(cls);
        }
    

    init

    我们可以看看它的实现:

    // Replaced by CF (throws an NSException)
    + (id)init {
        return (id)self;
    }
    
    - (id)init {
        return _objc_rootInit(self);
    }
    

    可以看出init返回的也是本身对象,它是工厂模式的一种表现形式,方便子类的重写与扩展。

    new

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

    可以看出,就是alloc 和 init的结合。

    最后,符号断点的三种调试技巧:

    1. 在对应的断点地方打上断点,然后按住Ctrl键,同时点击下图中圈出的部分,就会进入汇编页面


      断点调试1
      2.在对应的代码部分断点,然后用指定的断点搜索来查找对应的汇编部分,如下图: 断点调试2

    3.在对应的代码部分断点,然后等运行卡在断点部分,选择xcode顶部菜单栏中 Debug-->DebugWorkflow-->Always Show Disassembly,如下图:


    断点调试3

    相关文章

      网友评论

          本文标题:OC的对象原理之 alloc流程分析

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