alloc 流程分析

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

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

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

#import 
#import "Person.h"
#import 
#import 

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;
}

打印内容

-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 流程分析)