alloc的流程

首先展示一张oc对象alloc的流程图:
alloc.png
分析alloc的流程需要借助oc源码,oc源码可以去官网下载,也可以在逻辑cooci大神的GitHub地址下载,官网下载的源码需要自己配置才能编译成功,配置过程有点繁琐,cooci大神GitHub地址的源码是已经编译成功的,有需要的友友们可以自行选择下载。
接下来从这句
OCPeople *ocp = [[OCPeople alloc] init];断点进入探索流程,

1. 断点进入alloc,会发现内部调用了另外一个函数,代码如下:

+ (id)alloc {
    return _objc_rootAlloc(self);
}
复制代码

2. 断点进入_objc_rootAlloc,会发现这个函数向下层传递了两个参数checkNil和allocWithZone,代码如下:

_objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
复制代码

3. 断点进入callAlloc,这个函数里面出现了两个宏slowpath和fastpath,slowpath表示传入条件后结果为假的可能性很大,所以不会走if,也不会返回nil,fastpath表示传入条件后结果为真的可能性很大。__OBJC2__是判断是否为objc2.0版本,兼容objc1.0的逻辑,现在用的都是新版本objc2.0,所以会走这段if,代码如下:

// 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];
}
复制代码
3.1 根据上面的代码,fastpath(cls->canAllocFast())为真时,断点obj->initInstanceIsa(cls, dtor);进入initInstanceIsa看下,代码如下:
inline void 
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
    assert(!cls->instancesRequireRawIsa());
    assert(hasCxxDtor == cls->hasCxxDtor());

    initIsa(cls, true, hasCxxDtor);
}
复制代码
3.2 根据上面的代码,fastpath(cls->canAllocFast())为假时,断点id obj = class_createInstance(cls, 0);进入class_createInstance看下,里面调用了_class_createInstanceFromZone函数,代码如下:
id 
class_createInstance(Class cls, size_t extraBytes)
{
    return _class_createInstanceFromZone(cls, extraBytes, nil);
}
复制代码

4. 断点进入_class_createInstanceFromZone,这段代码就是alloc的核心,创建实例。size_t size = cls->instanceSize(extraBytes);是计算需要开辟的内存空间大小,传入的extraBytes为0;obj = (id)calloc(1, size);是向系统申请开辟内存空间;obj->initInstanceIsa(cls, hasCxxDtor);是将类cls和是否有c++析构器传入给initInstanceIsa,实例化isa,关联到相应的类,代码如下:

static __attribute__((always_inline)) 
id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, 
                              bool cxxConstruct = true, 
                              size_t *outAllocatedSize = nil)
{
    if (!cls) return nil;

    assert(cls->isRealized());

    // Read class's info bits all at once for performance
    bool hasCxxCtor = cls->hasCxxCtor();
    bool hasCxxDtor = cls->hasCxxDtor();
    bool fast = cls->canAllocNonpointer();

    size_t size = cls->instanceSize(extraBytes);
    if (outAllocatedSize) *outAllocatedSize = size;

    id obj;
    if (!zone  &&  fast) {
        obj = (id)calloc(1, size);
        if (!obj) return nil;
        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.
        obj->initIsa(cls);
    }

    if (cxxConstruct && hasCxxCtor) {
        obj = _objc_constructOrFree(obj, cls);
    }

    return obj;
}
复制代码

5. 断点进入size_t size = cls->instanceSize(extraBytes);看下instanceSize函数的实现,这段代码就是计算需要的内存空间大小,如果占用的内存空间<16,则返回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;
    }
复制代码

6. 断点进入alignedInstanceSize,内部调用了另外一个函数,代码如下:

// Class's ivar size rounded up to a pointer-size boundary.
    uint32_t alignedInstanceSize() {
        return word_align(unalignedInstanceSize());
    }
复制代码

7. word_align是字节对齐,参数unalignedInstanceSize是uint32_t类型,断点进入word_align,~WORD_MASK是WORD_MASK值取反的意思,(x + WORD_MASK) & ~WORD_MASK这一整句的意思是(x + WORD_MASK)的值和WORD_MASK取反的值进行与运算,x传入的是8,WORD_MASK现在是7,就是(8+7)&~7=00001111&~00000111=00001000,最后等于8,这个过程就是8字节对齐算法,取8的整数倍。这一句也等同于(x + WORD_MASK)>>3<<3,(x + WORD_MASK)右移3位再左移3位。word_align代码如下:

static inline uint32_t word_align(uint32_t x) {
    return (x + WORD_MASK) & ~WORD_MASK;
}
复制代码

以上就是alloc的探索过程中的部分代码,流程图会显示的详细些。alloc的核心就是开辟内存,通过isa指针关联到相应的类。
以上探索流程参考了cooci大神和学员的博客,感谢老师和同学们的分享!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享