美文网首页
retain的实现原理

retain的实现原理

作者: RingKun | 来源:发表于2020-06-29 15:42 被阅读0次

    1. retain的实现原理

    ALWAYS_INLINE id 
    objc_object::rootRetain(bool tryRetain, bool handleOverflow)
    {
        // TaggedPointer 不retain直接返回
        if (isTaggedPointer()) return (id)this;
    
        bool sideTableLocked = false;
        bool transcribeToSideTable = false;
    
        isa_t oldisa;
        isa_t newisa;
    
        do {
            // 默认不抄写到SideTable,isa指针5w+足以
            transcribeToSideTable = false;
            // 原子获取isa
            oldisa = LoadExclusive(&isa.bits);
            newisa = oldisa;
            
            // 非共用体isa, 一定会有一个结果,不会do-while的
            if (slowpath(!newisa.nonpointer)) {
                // 原子清空对象的isa.bits
                ClearExclusive(&isa.bits);
                // isa 指向原类,说明是类对象,直接返回
                if (rawISA()->isMetaClass())
                    return (id)this;
                // retain 必须成功返回true,那么如果当前线程锁住了sideTable对象,需要解锁。
                if (!tryRetain && sideTableLocked)
                    sidetable_unlock();
                if (tryRetain)
                    // try retain 会返回bool值以判定是否retain成功,由调用者自行do-while重试。
                    return sidetable_tryRetain() ? (id)this : nil;
                else
                    // retain 必须成功返回true,所以sidetable_retain会加lock。
                    return sidetable_retain();
            }
            
            // don't check newisa.fast_rr; we already called any RR overrides
            if (slowpath(tryRetain && newisa.deallocating)) {
                // 正在释放,原子清空isa.bits
                ClearExclusive(&isa.bits);
                if (!tryRetain && sideTableLocked)
                    // 释放sidetable资源
                    sidetable_unlock();
                return nil;
            }
            
            // 把new isa改一改,CAS操作失败继续do-while,直至成功
            uintptr_t carry;
            newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc++
    
            // isa extra_rc值超过2^19
            if (slowpath(carry)) {
                // 不处理越界,什么鬼?
                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加锁。如果等isa改完后再锁sidetable就完了。在isa和sidetable需要同时调整时,两件事是一个完成的事务。
                    sidetable_lock();
                // 标记下extra_rc满了extra_rc设置一半
                sideTableLocked = true;
                transcribeToSideTable = true;
                newisa.extra_rc = RC_HALF;
                newisa.has_sidetable_rc = true;
            }
        } while (slowpath(!StoreExclusive(&isa.bits, oldisa.bits, newisa.bits)));
    
        
        if (slowpath(transcribeToSideTable)) {
            // 拷贝另一半到side table. 那么为什么一人一半呢 ?
            // 因为,isa操作快啊
            // 那么为什么不全拷贝过去?
            // 因为还要release,ISA减到0又要拷贝部分过来不是吗,所以是兄弟就AA吧。
            sidetable_addExtraRC_nolock(RC_HALF);
        }
        // 所有操作完成,解锁
        if (slowpath(!tryRetain && sideTableLocked)) sidetable_unlock();
        return (id)this;
    }
    -------------
    id
    objc_object::sidetable_retain()
    {
    #if SUPPORT_NONPOINTER_ISA
        ASSERT(!isa.nonpointer);
    #endif
        SideTable& table = SideTables()[this];
        
        table.lock();
        size_t& refcntStorage = table.refcnts[this];
        if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {
            refcntStorage += SIDE_TABLE_RC_ONE;
        }
        table.unlock();
    
        return (id)this;
    }
    
    • 注意点:
    1. 修改ISA通过自旋CAS完成,在这种场景下,冲突的可能性小,性能高。
    2. 修改SideTables时通过加锁完成,所以性能会差很多(weak引用同理)
    3. 为了权衡isa 2^19的空间限制问题和性能问题,Apple采用了HALF_RC平均分配(还有release,需要考虑isa extra_rc减到0需要拷贝回来的问题)。
    4. extra_rc 与 sideTable需要同时,需要注意事务的原子性和隔离性,提前加锁。

    release和retain的原理和注意点相似,倒过来就好了。

    相关文章

      网友评论

          本文标题:retain的实现原理

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