Retain 和 Release

2020-11-27  本文已影响0人  forping

属性的setter和getter方法 中,我们可以发现, objc_retain 方法被调用.
那么对象的引用计数管理,是怎么进行的呢?

- (void)testWeak{    
    NSObject *objct = [[NSObject alloc] init];
    NSObject *o2 = objct;
    o2 = nil;
}

arm64 汇编

"-[A testWeak]":                        ; @"\01-[A testWeak]"
    sub sp, sp, #80             ; =80 ; sp = sp - 80
    stp x29, x30, [sp, #64]     ; 16-byte Folded Spill  将 x29 和 x30 的值存储到 sp+64
    add x29, sp, #64            ; =64  x29 = sp+64
    stur    x0, [x29, #-8] ;  sp + 56  = x0 = self
    stur    x1, [x29, #-16]  sp + 48  =  x1 = SEL
    adrp    x8, _OBJC_CLASSLIST_REFERENCES_$_@PAGE  ;  加载 类对象列表  base地址,存储到x8
    add x8, x8, _OBJC_CLASSLIST_REFERENCES_$_@PAGEOFF ;  根据偏移量计算 NSObject 的类对象地址, 地址 x8 = x8 + 偏移地址
    ldr x0, [x8] ;  x0 = x8;
    bl  _objc_alloc ; 调用  id _Nullable objc_alloc(Class _Nullable cls) 方法
    adrp    x8, _OBJC_SELECTOR_REFERENCES_@PAGE; 加载方法列表  base地址,存储到x8
    add x8, x8, _OBJC_SELECTOR_REFERENCES_@PAGEOFF ; 根据偏移量计算 NSObject 的 -(instancetype)init 方法地址, 地址 x8 = x8 + 偏移地址
    ldr x1, [x8]  ; -(instancetype)init 方法放到x1
    bl  _objc_msgSend  ; 调用init方法, 
    sub x8, x29, #24            ; =24; x8 = sp+40;
    stur    x0, [x29, #-24] ; x0 存储到  sp+40  = object,对应了 NSObject *objct = [[NSObject alloc] init]; 代码
    ldur    x0, [x29, #-24] ; sp+40存储到x0  = object
    str x8, [sp, #24]           ; 8-byte Folded Spill , x8 放到  sp + 24 = object

    bl  _objc_retain ;  调用 _objc_retain 方法, 类似 [objct retain]; 此时引用计数器的值为 2

    add x8, sp, #32             ; =32   x8 = sp+32

    str x0, [sp, #32] ; x0 放到 sp + 32  = object 对应NSObject *o2 = objct; 代码

    mov x0, x8 ; x0 = x8 = sp+32 = o2;
    mov x9, #0; x9 = 0  
    mov x1, x9; x1 = 0; 
    str x8, [sp, #16]           ; 8-byte Folded Spill ; sp+16 = x0 = o2
    str x9, [sp, #8]            ; 8-byte Folded Spill sp+8 = x9 = 0;

    bl  _objc_storeStrong ;  调用 void objc_storeStrong(id *location, id obj)方法  对应了o2 = nil; 方法

    ldr x0, [sp, #16]           ; 8-byte Folded Reload  x0 = sp + 16; = o2
    ldr x1, [sp, #8]            ; 8-byte Folded Reload  x1 = sp+8 = 0; 释放 o2

    bl  _objc_storeStrong ; 作用域结束, object = nil

    ldr x0, [sp, #24]           ; 8-byte Folded Reload  x0 = sp + 24 = object;
    ldr x1, [sp, #8]            ; 8-byte Folded Reload x1 = sp + 8 = 0;

    bl  _objc_storeStrong ; 释放对象

    ldp x29, x30, [sp, #64]     ; 16-byte Folded Reload
    add sp, sp, #80             ; =80
    ret

可以看到

NSObject对象的创建调用了 objc_alloc 函数

关于对象的内存分配和类的关联可以看下面的文章
https://www.jianshu.com/p/532ddbf803a2

引用计数的管理,主要体现在objc_retain``objc_storeStrong方法中,
可能会想, 对象刚创建出来,引用计数为1, 那么怎么赋值的呢, 但其实是因为引用计数器存储的值是引用计数器减1

在目前最新的源码,818.2中,创建对象后引用计数会赋值为1,引用计数器存储的值直接就是引用计数了

objc_retain 和 retain

objc_retain
id objc_retain(id obj)
{
    if (!obj) return obj;
    if (obj->isTaggedPointer()) return obj;
    return obj->retain();
}
id objc_object::retain()
{
    ASSERT(!isTaggedPointer());

    return rootRetain(false, RRVariant::FastOrMsgSend);
}

rootRetain 这个函数来增加引用计数

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

    bool sideTableLocked = false;
    bool transcribeToSideTable = false;

    isa_t oldisa;
    isa_t newisa;

    oldisa = LoadExclusive(&isa.bits);

    if (variant == RRVariant::FastOrMsgSend) { // 主要检查是否需要调用objc_msgSend 
        // These checks are only meaningful for objc_retain()
        // They are here so that we avoid a re-load of the isa.
        if (slowpath(oldisa.getDecodedClass(false)->hasCustomRR())) { // 如果具有默认的retain/release/autorelease/方法
            ClearExclusive(&isa.bits);
            if (oldisa.getDecodedClass(false)->canCallSwiftRR()) {
                return swiftRetain.load(memory_order_relaxed)((id)this);
            }
            return ((id(*)(objc_object *, SEL))objc_msgSend)(this, @selector(retain));
        }
    }

    if (slowpath(!oldisa.nonpointer)) { 
        // a Class is a Class forever, so we can perform this check once
        // outside of the CAS loop
        if (oldisa.getDecodedClass(false)->isMetaClass()) { //检查isa是不是元类对象,
            ClearExclusive(&isa.bits);
            return (id)this;
        }
    }

    do {
        transcribeToSideTable = false;
        newisa = oldisa; // 创建一个临时的isa:newisa,操作都是针对临时变量来操作,最后将newisa的bits信息存储到原始的isa中去,有个do-while去处理存储的逻辑,失败的话就重试
        if (slowpath(!newisa.nonpointer)) { // 不是优化过的指针,直接使用sidetable存储计数
            ClearExclusive(&isa.bits);
            if (tryRetain) return sidetable_tryRetain() ? (id)this : nil;
            else return sidetable_retain(sideTableLocked);
        }
        // don't check newisa.fast_rr; we already called any RR overrides
        if (slowpath(newisa.isDeallocating())) { // 如果当前正在释放
            ClearExclusive(&isa.bits);
            if (sideTableLocked) {
                ASSERT(variant == RRVariant::Full);
                sidetable_unlock();
            }
            if (slowpath(tryRetain)) { // 直接返回 不增加引用计数
                return nil;
            } else {
                return (id)this;
            }
        }
        uintptr_t carry;
        newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc++ 增加引用计数, carry表示数值是否溢出

        if (slowpath(carry)) {
            // newisa.extra_rc++ overflowed
            if (variant != RRVariant::Full) { // 如果溢出,且当前不是溢出状态,就设置为溢出状态,并且重新调用方法
                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;
            newisa.extra_rc = RC_HALF; // 引用计数减为一半
            newisa.has_sidetable_rc = true; // 有引用计数在sidetable里存储
        }
    } while (slowpath(!StoreExclusive(&isa.bits, &oldisa.bits, newisa.bits)));

    if (variant == RRVariant::Full) { // 如果是满的,且  transcribeToSideTable == true
        if (slowpath(transcribeToSideTable)) {
            // Copy the other half of the retain counts to the side table.
            sidetable_addExtraRC_nolock(RC_HALF); // 存储到sidetable
        }

        if (slowpath(!tryRetain && sideTableLocked)) sidetable_unlock();
    } else {
        ASSERT(!transcribeToSideTable);
        ASSERT(!sideTableLocked);
    }

    return (id)this;
}

sidetable_addExtraRC_nolock

bool  objc_object::sidetable_addExtraRC_nolock(size_t delta_rc)
{
    ASSERT(isa.nonpointer); 
    SideTable& table = SideTables()[this];
    // 获取当前的引用计数
    size_t& refcntStorage = table.refcnts[this];
    size_t oldRefcnt = refcntStorage;
    // isa-side bits should not be set here
    ASSERT((oldRefcnt & SIDE_TABLE_DEALLOCATING) == 0); // 正在释放

    ASSERT((oldRefcnt & SIDE_TABLE_WEAKLY_REFERENCED) == 0); // 弱引用正在释放
    // 系统计数极限了,直接true
    if (oldRefcnt & SIDE_TABLE_RC_PINNED) return true;

    uintptr_t carry;
// 增加引用计数
    size_t newRefcnt = 
        addc(oldRefcnt, delta_rc << SIDE_TABLE_RC_SHIFT, 0, &carry);
    if (carry) {
        // 如果借位保存在这里还溢出,就当做SIDE_TABLE_RC_PINNED次数(32或64最大位数-1的数值)
        refcntStorage =
            SIDE_TABLE_RC_PINNED | (oldRefcnt & SIDE_TABLE_FLAG_MASK);
        return true;
    }
    else {
        refcntStorage = newRefcnt;
        return false;
    }
}

直接通过 sidetable_retain增加引用计数

id
objc_object::sidetable_retain()
{
#if SUPPORT_NONPOINTER_ISA // 是否支持优化过的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; // // 引用计数加1,(偏移2位,SIDE_TABLE_RC_ONE = 1<<2)
    }
    table.unlock();
    return (id)this;
}

retain

当我们在MRC手动调用 retain 方法时

- (id)retain {
    return _objc_rootRetain(self);
}
id _objc_rootRetain(id obj)
{
    ASSERT(obj);

    return obj->rootRetain();
}

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

最后也调用到rootRetain

获取对象的引用计数

- (NSUInteger)retainCount {
    return _objc_rootRetainCount(self);
}
_objc_rootRetainCount(id obj)
{
    ASSERT(obj);

    return obj->rootRetainCount();
}

rootRetainCount

inline uintptr_t  objc_object::rootRetainCount()
{
    //TaggedPointer指针 直接返回
    if (isTaggedPointer()) return (uintptr_t)this;
    sidetable_lock();
    isa_t bits = __c11_atomic_load((_Atomic uintptr_t *)&isa.bits, __ATOMIC_RELAXED);
    //优化过的 isa 指针
    if (bits.nonpointer) {
        uintptr_t rc = bits.extra_rc; // extra_rc存储的计数数量
        if (bits.has_sidetable_rc) { //bits.has_sidetable_rc标志位为1 表明有存放在sidetable中的引用计数
//读取table的值 相加
            rc += sidetable_getExtraRC_nolock();
        }
        sidetable_unlock();
        return rc;
    }

    sidetable_unlock();
    //如果没采用优化的isa指针,则直接返回sidetable中的值
    return sidetable_retainCount();
}

retainCount = isa.extra_rc + sidetable_getExtraRC_nolock,即引用计数=isa指针中存储的引用计数+sidetable中存储的引用计数

size_t  objc_object::sidetable_getExtraRC_nolock()
{
    ASSERT(isa.nonpointer);
    //key是 this,存储了对象的table
    SideTable& table = SideTables()[this];
    //找到 it 否则返回0
    // 这里返回的it是RefcountMap类型 it == table.refcnts.end() 
    // 表示在sidetable中没有找到this对应的引用计数则直接返回0
    RefcountMap::iterator it = table.refcnts.find(this);
    if (it == table.refcnts.end()) return 0;
 // RefcountMap 结构的second值为引用计数值 
    // DenseMap<DisguisedPtr<objc_object>,size_t,true> RefcountMap;
        // it->second 无符号整型,真实的引用计数需要右移2位
    else return it->second >> SIDE_TABLE_RC_SHIFT;
}

objc_storeStrong

// location是引用对象的指针的地址,obj是对象本身。
void objc_storeStrong(id *location, id obj)
{
// 取到指针指的旧对象
    id prev = *location;
    if (obj == prev) {
        return;
    }
    objc_retain(obj); // 新对象计数+1
    *location = obj;
    objc_release(prev); // 旧对象计数-1
}

objc_release

void  objc_release(id obj)
{
    if (obj->isTaggedPointerOrNil()) return;
    return obj->release();
}
inline void
objc_object::release()
{
    ASSERT(!isTaggedPointer());

    rootRelease(true, RRVariant::FastOrMsgSend);
}

rootRelease

ALWAYS_INLINE bool
objc_object::rootRelease(bool performDealloc, objc_object::RRVariant variant)
{
    if (slowpath(isTaggedPointer())) return false;

    bool sideTableLocked = false;

    isa_t newisa, oldisa;
// 获取isa
    oldisa = LoadExclusive(&isa.bits);
// 是否有自己的 release 方法
    if (variant == RRVariant::FastOrMsgSend) {
        // These checks are only meaningful for objc_release()
        // They are here so that we avoid a re-load of the isa.
        if (slowpath(oldisa.getDecodedClass(false)->hasCustomRR())) {
            ClearExclusive(&isa.bits);
            if (oldisa.getDecodedClass(false)->canCallSwiftRR()) {
                swiftRelease.load(memory_order_relaxed)((id)this);
                return true;
            }
            ((void(*)(objc_object *, SEL))objc_msgSend)(this, @selector(release));
            return true;
        }
    }
     // 是否是元类
    if (slowpath(!oldisa.nonpointer)) {
        // a Class is a Class forever, so we can perform this check once
        // outside of the CAS loop
        if (oldisa.getDecodedClass(false)->isMetaClass()) {
            ClearExclusive(&isa.bits);
            return false;
        }
    }

retry:
    do {
// 临时变量
        newisa = oldisa;
        if (slowpath(!newisa.nonpointer)) {
            ClearExclusive(&isa.bits);
// 不是优化过的isa 直接release
            return sidetable_release(sideTableLocked, performDealloc);
        }
// 正在释放,返回失败
        if (slowpath(newisa.isDeallocating())) {
            ClearExclusive(&isa.bits);
            if (sideTableLocked) {
                ASSERT(variant == RRVariant::Full);
                sidetable_unlock();
            }
            return false;
        }

        // don't check newisa.fast_rr; we already called any RR overrides
        uintptr_t carry;
        newisa.bits = subc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc--
        // 不够减,直接去 underflow 
        if (slowpath(carry)) {
            // don't ClearExclusive()
            goto underflow;
        }
    } while (slowpath(!StoreReleaseExclusive(&isa.bits, &oldisa.bits, newisa.bits))); // 合并

    if (slowpath(newisa.isDeallocating())) // 是否需要释放
        goto deallocate; 

    if (variant == RRVariant::Full) {
        if (slowpath(sideTableLocked)) sidetable_unlock();
    } else {
        ASSERT(!sideTableLocked);
    }
    return false;

 underflow:
    // newisa.extra_rc-- underflowed: borrow from side table or deallocate

    // abandon newisa to undo the decrement
    newisa = oldisa;

    if (slowpath(newisa.has_sidetable_rc)) { // sidetable 是否存有引用计数
        if (variant != RRVariant::Full) {
            ClearExclusive(&isa.bits);
            return rootRelease_underflow(performDealloc); // 再次调用自己,只不过第二个参数是full
        }

        // Transfer retain count from side table to inline storage.

        if (!sideTableLocked) {
            ClearExclusive(&isa.bits);
            sidetable_lock();
            sideTableLocked = true;
            // Need to start over to avoid a race against 
            // the nonpointer -> raw pointer transition.
            oldisa = LoadExclusive(&isa.bits);
            goto retry; // 重新去减少引用计数
        }

        // 从sidetable分出来一部分引用计数
        // Try to remove some retain counts from the side table.        
        auto borrow = sidetable_subExtraRC_nolock(RC_HALF);
        // 是不是空的表
        bool emptySideTable = borrow.remaining == 0; // we'll clear the side table if no refcounts remain there

        if (borrow.borrowed > 0) {
            // Side table retain count decreased.
            // Try to add them to the inline count.
            bool didTransitionToDeallocating = false;
// 增加 extra_rc 的值 ,但是要减去1.就不用再去减了
            newisa.extra_rc = borrow.borrowed - 1;  // redo the original decrement too
            newisa.has_sidetable_rc = !emptySideTable;

            bool stored = StoreReleaseExclusive(&isa.bits, &oldisa.bits, newisa.bits); // 合并

            if (!stored && oldisa.nonpointer) { // 合并失败,立刻重试
                uintptr_t overflow;
                newisa.bits =
                    addc(oldisa.bits, RC_ONE * (borrow.borrowed-1), 0, &overflow);
                newisa.has_sidetable_rc = !emptySideTable;
                if (!overflow) {
                    stored = StoreReleaseExclusive(&isa.bits, &oldisa.bits, newisa.bits);
                    if (stored) {
                        didTransitionToDeallocating = newisa.isDeallocating(); // 是否需要释放
                    }
                }
            }

            if (!stored) { // 还是合并失败,重新去走 retry 流程
                ClearExclusive(&isa.bits);
                sidetable_addExtraRC_nolock(borrow.borrowed);
                oldisa = LoadExclusive(&isa.bits);
                goto retry;
            }

            // Decrement successful after borrowing from side table.
            if (emptySideTable) // 空表,去释放表
                sidetable_clearExtraRC_nolock();

            if (!didTransitionToDeallocating) { // 不需要释放就返回
                if (slowpath(sideTableLocked)) sidetable_unlock();
                return false;
            }
        }
        else {
            // Side table is empty after all. Fall-through to the dealloc path.
        }
    }

deallocate:
    // 开始释放

    ASSERT(newisa.isDeallocating());
    ASSERT(isa.isDeallocating());

    if (slowpath(sideTableLocked)) sidetable_unlock();

    __c11_atomic_thread_fence(__ATOMIC_ACQUIRE);

    if (performDealloc) { // 调用dealloc方法
        ((void(*)(objc_object *, SEL))objc_msgSend)(this, @selector(dealloc));
    }
    return true;
}

sidetable_subExtraRC_nolock 从sidetable分出来一部分引用计数

objc_object::SidetableBorrow objc_object::sidetable_subExtraRC_nolock(size_t delta_rc)
{
    ASSERT(isa.nonpointer);
    SideTable& table = SideTables()[this];

    RefcountMap::iterator it = table.refcnts.find(this);
    if (it == table.refcnts.end()  ||  it->second == 0) {
        // Side table retain count is zero. Can't borrow.
// Side table 没有引用计数
        return { 0, 0 };
    }
    size_t oldRefcnt = it->second;

    // isa-side bits should not be set here
    ASSERT((oldRefcnt & SIDE_TABLE_DEALLOCATING) == 0);
    ASSERT((oldRefcnt & SIDE_TABLE_WEAKLY_REFERENCED) == 0);
  // 分出去引用计数 ,返回分出去的引用计数和剩余的引用计数
    size_t newRefcnt = oldRefcnt - (delta_rc << SIDE_TABLE_RC_SHIFT);
    ASSERT(oldRefcnt > newRefcnt);  // shouldn't underflow
    it->second = newRefcnt;
    return { delta_rc, newRefcnt >> SIDE_TABLE_RC_SHIFT };
}

release

// Replaced by ObjectAlloc
- (oneway void)release {
    _objc_rootRelease(self);
}
NEVER_INLINE void _objc_rootRelease(id obj)
{
    ASSERT(obj);

    obj->rootRelease(); // 也调用到了上面的方法
}

也就是说,在引用计数减少的时候判断是否去释放

hasCustomRR()

// hasCustomRR函数通过掩码计算,检查类(包括其父类)中是否含有默认的方法,并且有则调用默认的方法;如果没有,调用其他方法.
bool hasCustomRR() const {
        return !(bits.data()->flags & RW_HAS_DEFAULT_RR);
}

 class_rw_t* data() const {
        return (class_rw_t *)(bits & FAST_DATA_MASK);
}
上一篇下一篇

猜你喜欢

热点阅读