iOS 底层探索篇 —— alloc 流程|8月更文挑战

168 阅读2分钟

1. alloc

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

在 alloc 中实际调用了 _objc_rootAlloc 的方法,并把自己作为参数传入方法中。

2. _objc_rootAlloc

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

在_objc_rootAlloc 实际调用了 callAlloc 方法,并传入三个参数

  1. 对象的class
  2. 是否checkNil
  3. 以及是否allocWithZone

3. callAlloc

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

} 在 callAlloc 中,

  1. 如果编译器处于不优化模式,并且checkNil 为true 以及 cls 不为空的情况下,返回空。
  2. 如果编译器处于优化模式,并且cls没有自定义的allocWithZone,没有的话就调用,_objc_rootAllocWithZone方法,
  3. 如果编译器有自定义的allocWithZone,则调用自定义的allocWithZone

4. _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方法

5. _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
bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
bool hasCxxDtor = cls->hasCxxDtor();
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);

}

在这个方法中

  1. 声明 obj 时候(id obj)会有一个地址,系统会分配一个脏地址。
  2. size = cls->instanceSize(extraBytes); ,这个决定了开辟内存的大小,大小由成员变量决定,如果小于16则返回16。如果大于16,需要用字节对齐,返回8的倍数。
  3. 在calloc 之后,会申请内存,并将地址返回替换掉obj的脏地址,此时地址还未绑定类,关联类的是isa。
  4. 在 obj->initInstanceIsa(cls, hasCxxDtor); 之后,地址绑定类

流程图

在这里插入图片描述