美文网首页
alloc 流程分析

alloc 流程分析

作者: SuperMan_Wang | 来源:发表于2021-04-02 15:28 被阅读0次

    在开发过程中 我们一般使用 [[NSObject alloc] init] 的方式来创建一个对象,那么在 调用 alloc 方法是,系统都是做了什么呢?接下来我们来一探究竟。

    此处可以获得objc源码 打开源码,我们使用源码进行分析。

    这里我自定义一个Person类,继承自NSObject

    #import <Foundation/Foundation.h>
    #import "Person.h"
    #import <objc/runtime.h>
    #import <malloc/malloc.h>
    
    int main(int argc, const char * argv[]) {
    
        @autoreleasepool {
    
            Person* person1 = [Person alloc];
            Person* person2 = [Person alloc];
    
            NSLog(@"%@-%lu-%lu-%lu",
                  person1,
                  class_getInstanceSize([person1 class]) ,
                  sizeof(&person1),
                  malloc_size((__bridge const void *)(person1)) );
        }
        return 0;
    }
    

    打印内容

    <Person: 0x1007164a0>-8-8-16
    

    最开始,调用 alloc方法 断点进去 会调用到

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

    再接着是

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

    接着断点来到了

    
    static ALWAYS_INLINE id
    
    callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
    
    {
    
    #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));
    
    }
    

    这里,之后是

    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(cls, 0, nil, OBJECT_CONSTRUCT_CALL_BADALLOC) 方法。 我们来到此方法的内部这就是重点了;
    方法具体的实现如下:

    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
    
        bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
    
        bool hasCxxDtor = cls->hasCxxDtor();
    
        bool fast = cls->canAllocNonpointer();
    
        size_t size;
    
    
    
        size = cls->instanceSize(extraBytes); // 1
    
        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); // 2
    
        }
    
        if (slowpath(!obj)) {
    
            if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
    
                return _objc_callBadAllocHandler(cls);
    
            }
    
            return nil;
    
        }
    
    
    
        if (!zone && fast) {
    
            obj->initInstanceIsa(cls, hasCxxDtor); // 3
    
        } 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);
    
    }
    

    方法内部 最重要的是以下三部分内容:

    • 首先,会通过cls->instanceSize(extraBytes) 来计算出需要的内存空间大小;
    • 接着,使用 (id)calloc(1, size)来向系统申请开辟内存空间,返回地址指针;
    • 最后,使用obj->initInstanceIsa(cls, hasCxxDtor) 来将类和指针做绑定。

    其中在计算内存空间大小时,会调用 cache.fastInstanceSize(extraBytes) 方法,
    最终会调用 align16(size + extra - FAST_CACHE_ALLOC_DELTA16) 方法

    align16 的实现如下:

    
    static inline size_t align16(size_t x) {
    
        return (x + size_t(15)) & ~size_t(15);
    
    }
    

    此方法其实是 系统进行 16字节 的对齐操作, 也就是说, 一个对象所占用的内存大小至少是16字节。

    相关文章

      网友评论

          本文标题:alloc 流程分析

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