iOS中对象内存管理的探讨

在OC对象的alloc过程一文中,我们一起探讨了alloc的过程,接下来我们就对对象的retain、release、dealloc过程进行探讨。

retain

首先我们看下 rootRetain的源码实现

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

    bool sideTableLocked = false;
    bool transcribeToSideTable = false;

    isa_t oldisa;
    isa_t newisa;

    do {
        transcribeToSideTable = false;
        oldisa = LoadExclusive(&isa.bits);
        newisa = oldisa;
        if (slowpath(!newisa.nonpointer)) {
            ClearExclusive(&isa.bits);
            if (rawISA()->isMetaClass()) return (id)this;
            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;
        newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc++

        if (slowpath(carry)) {
            // newisa.extra_rc++ overflowed
            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;
            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;
}

首先,会判断当前 是否为 taggedPointer,如果是就直接返回。然后会操作散列表(SideTable),在 sidetable_unlock方法中

void 
objc_object::sidetable_unlock()
{
    SideTable& table = SideTables()[this];
    table.unlock();
}

SideTablesMap中以thiskey得到该散列表,在内存中有多个散列表,是通过Map进行存放的,一共有 64张散列表。为什么会有多张散列表呢?因为我们对引用计数进行管理时,都需要解锁上锁,性能不好。
SideTable结构体中

struct SideTable {
    spinlock_t slock;
    RefcountMap refcnts;
    weak_table_t weak_table;

    SideTable() {
        memset(&weak_table, 0, sizeof(weak_table));
    }

    ~SideTable() {
        _objc_fatal("Do not delete SideTable.");
    }

    void lock() { slock.lock(); }
    void unlock() { slock.unlock(); }
    void forceReset() { slock.forceReset(); }

    // Address-ordered lock discipline for a pair of side tables.

    template
    static void lockTwo(SideTable *lock1, SideTable *lock2);
    template
    static void unlockTwo(SideTable *lock1, SideTable *lock2);
};

有一把锁 spinlock_t,存放引用对象的引用计数表RefcountMap,和一张弱引用表weak_table_t

第二步判断当前对象是否在deallocing状态,如果是正在dealloc,流程就进入到了 dealloc阶段,dealloc的过程在文章的下个阶段有介绍。
第三步,对isa的bits进行处理,对 extra_rc进行 +1,如果 extra_rc满了,就操作散列表。将满状态extra_rc的一半移到散列表中,将 has_sidetable_rc状态位设置为 true,表示现在依赖散列表了。

release

release 的过程和retain的过程类似,retain是对extra_rc进行相加,release是对extra_rc相减。

objc_object::rootRelease(bool performDealloc, bool handleUnderflow)
{
    if (isTaggedPointer()) return false;

    bool sideTableLocked = false;

    isa_t oldisa;
    isa_t newisa;

 retry:
    do {
        oldisa = LoadExclusive(&isa.bits);
        newisa = oldisa;
        if (slowpath(!newisa.nonpointer)) {
            ClearExclusive(&isa.bits);
            if (rawISA()->isMetaClass()) return false;
            if (sideTableLocked) sidetable_unlock();
            return sidetable_release(performDealloc);
        }
        // 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--
        if (slowpath(carry)) {
            // don't ClearExclusive()
            goto underflow;
        }
    } while (slowpath(!StoreReleaseExclusive(&isa.bits, 
                                             oldisa.bits, newisa.bits)));

    if (slowpath(sideTableLocked)) sidetable_unlock();
    return false;
underflow:
   ......
}

extra_rc进行减法运算使用的是 subc函数,如果extra_rc为0(empty)了,就会在散列表里面进行查找减1。当extra_rc为空且散列表里面的也为空,则将 deallocing 设置为 true,对该对象进行析构(dealloc)

root_dealloc

其源码实现如下

inline void
objc_object::rootDealloc()
{
    if (isTaggedPointer()) return;  // fixme necessary?

    if (fastpath(isa.nonpointer  &&  
                 !isa.weakly_referenced  &&  
                 !isa.has_assoc  &&  
                 !isa.has_cxx_dtor  &&  
                 !isa.has_sidetable_rc))
    {
        assert(!sidetable_present());
        free(this);
    } 
    else {
        object_dispose((id)this);
    }
}

对象在释放的时候,要 清除对象的关联对象,调用其cxx析构函数,清空弱引用表,清空散列表里面的引用计数表,最后进行free
objc_destructInstance方法中,如果有弱引用(weak_reference)会将其弱引用表进行清空(erase)。如果有has_sidetable_rc,将其存放引用计数的sidetable清空。

你可能感兴趣的:(iOS中对象内存管理的探讨)