0
点赞
收藏
分享

微信扫一扫

iOS增加引用计数

舍予兄 2022-01-09 阅读 48

1、对象调用retain函数会增加引用计数


// Replaced by ObjectAlloc
- (id)retain {
    return ((id)self)->rootRetain();
}

2、rootRetain函数


ALWAYS_INLINE id 
objc_object::rootRetain()
{
    return rootRetain(false, false);
}


ALWAYS_INLINE id 
objc_object::rootRetain(bool tryRetain, bool handleOverflow)
{
    if (isTaggedPointer()) return (id)this;

    bool sideTableLocked = false;
    //标记是否把引用计数存到SideTable引用计数表中,默认false,因为对象的引用引用计数首先保存到isa的extra_rc中,如果extra_rc存满了,再保存到SideTable引用计数表中
    bool transcribeToSideTable = false;

    isa_t oldisa;
    isa_t newisa;

    do {
        transcribeToSideTable = false;
        oldisa = LoadExclusive(&isa.bits);//获取isa的值
        newisa = oldisa;
        if (slowpath(!newisa.nonpointer)) {//如果是tagpointer类型的对象走这里,因为tagpointer类型的对象没有isa指针
            ClearExclusive(&isa.bits);
            if (!tryRetain && sideTableLocked) sidetable_unlock();
            if (tryRetain) return sidetable_tryRetain() ? (id)this : nil;
            else return sidetable_retain();
        }
        // don't check newisa.fast_rr; we already called any RR overrides
        if (slowpath(tryRetain && newisa.deallocating)) {
            ClearExclusive(&isa.bits);
            if (!tryRetain && sideTableLocked) sidetable_unlock();
            return nil;
        }
        uintptr_t carry;
        //先在isa的extra_rc上加1保存引用计数,如果extra_rc存满了,通过carry标记,判断是否在SideTable引用计数表保存
        newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc++

        if (slowpath(carry)) {
            // newisa.extra_rc++ overflowed
            //如果extra_rc存满了,就存到SideTable引用计数表
            if (!handleOverflow) {
                ClearExclusive(&isa.bits);
                return rootRetain_overflow(tryRetain);
            }
            // Leave half of the retain counts inline and 
            // prepare to copy the other half to the side table.
            if (!tryRetain && !sideTableLocked) sidetable_lock();
            sideTableLocked = true;
            transcribeToSideTable = true;//标记为存到SideTable引用计数表中
            newisa.extra_rc = RC_HALF;//标记为已经满了
            newisa.has_sidetable_rc = true;//标记为使用引用计数表
        }
    } while (slowpath(!StoreExclusive(&isa.bits, oldisa.bits, newisa.bits)));

    if (slowpath(transcribeToSideTable)) {
        // Copy the other half of the retain counts to the side table.
        sidetable_addExtraRC_nolock(RC_HALF);
    }

    if (slowpath(!tryRetain && sideTableLocked)) sidetable_unlock();
    return (id)this;
}

3、addc这个方法把isa中保存的引用计数进行加1

static ALWAYS_INLINE uintptr_t 
addc(uintptr_t lhs, uintptr_t rhs, uintptr_t carryin, uintptr_t *carryout)
{
    return __builtin_addcl(lhs, rhs, carryin, carryout);
}

4、sidetable_retain函数把引用计数表上的加1

//把对象的引用计数加1
id
objc_object::sidetable_retain()
{
#if SUPPORT_NONPOINTER_ISA
    assert(!isa.nonpointer);
#endif
    //根据对象的地址获取所对应的SideTable引用计数表
    SideTable& table = SideTables()[this];
    
    table.lock();
    //再根据对象的地址经过哈希运算之后获取对象的的引用计数大小
    size_t& refcntStorage = table.refcnts[this];
    if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {
        refcntStorage += SIDE_TABLE_RC_ONE;//在这里进行加1
    }
    table.unlock();

    return (id)this;
}
举报

相关推荐

0 条评论