18 - 內(nèi)存管理之retain/release/dealloc/retainCount的底層分析

OC底層原理探索文檔匯總

本文主要是在源碼層面上分析內(nèi)存管理的引用計(jì)數(shù)的變化過程以及。包括alloc/retain/release/dealloc/retainCount的源碼分析

主要內(nèi)容:
1、引用計(jì)數(shù)的過程
2、弱引用表的結(jié)構(gòu)
3、sideTable散列表的結(jié)構(gòu)

retain的分析

retain

在源碼中全局搜索retain()

源碼:

// Equivalent to calling [this retain], with shortcuts if there is no override
//相當(dāng)于調(diào)用[this retain],如果沒有重寫,則使用快捷方式
inline id 
objc_object::retain()
{
    ASSERT(!isTaggedPointer());

    //如果沒有重寫retain方法,就會(huì)執(zhí)行默認(rèn)的
    if (fastpath(!ISA()->hasCustomRR())) {
        return rootRetain();
    }

    //如果本類已經(jīng)重寫了,就和普通的方法調(diào)用一樣直接調(diào)用重寫的方法即可
    return ((id(*)(objc_object *, SEL))objc_msgSend)(this, @selector(retain));
}

說明:

  • 如果我們重寫了retain方法,會(huì)進(jìn)行消息發(fā)送來(lái)調(diào)用
  • 如果沒有重寫,就直接調(diào)用已有的rootRetain函數(shù)
  • 因此我們平時(shí)要重寫retain方法就需要[super retain]

rootRetain

通過retain -> rootRetain() -> rootRetain(bool tryRetain, bool handleOverflow),找到rootRetain函數(shù)進(jìn)行分析

源碼:

/*
 進(jìn)行一次reatain真正進(jìn)行的操作
 過程:
    1、如果不是nonpointr_isa,就直接操作散列表
    2、如果正在釋放,就直接dealloc
    3、引用計(jì)數(shù)+1
    4、判斷如果carry已經(jīng)滿了,就將引用計(jì)數(shù)的一半放到散列表中,一半放到extra_rc中
 */
ALWAYS_INLINE id 
objc_object::rootRetain(bool tryRetain, bool handleOverflow)
{
    if (isTaggedPointer()) return (id)this;//小對(duì)象類型直接返回,不進(jìn)行任何操作

    bool sideTableLocked = false;
    bool transcribeToSideTable = false;//轉(zhuǎn)移到sideTable

    //這里使用isa是因?yàn)閕sa中存儲(chǔ)有引用計(jì)數(shù)
    isa_t oldisa;
    isa_t newisa;

    do {
        transcribeToSideTable = false;
        oldisa = LoadExclusive(&isa.bits);
        newisa = oldisa;
        //判斷是否為nonpointer isa
        if (slowpath(!newisa.nonpointer)) {
            //如果不是 nonpointer isa,直接操作散列表sidetable
            ClearExclusive(&isa.bits);
            if (rawISA()->isMetaClass()) return (id)this;//如果是元類,直接返回當(dāng)前對(duì)象
            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
        //是否正在釋放,直接dealloc
        if (slowpath(tryRetain && newisa.deallocating)) {
            ClearExclusive(&isa.bits);
            if (!tryRetain && sideTableLocked) sidetable_unlock();
            return nil;
        }
        uintptr_t carry;
        //執(zhí)行引用計(jì)數(shù)+1操作,即對(duì)bits中的extra_rc進(jìn)行+1操作,通過1ULL<<45(arm64,用于該對(duì)象存儲(chǔ)引用計(jì)數(shù)值
        //狀態(tài)標(biāo)識(shí)carry,用于表示extra_rc是否滿了
        newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc++

        //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.
            //這里只將一半存入到extra_rc中,剩下的一半存儲(chǔ)到散列表中
            if (!tryRetain && !sideTableLocked) sidetable_lock();
            sideTableLocked = true;
            transcribeToSideTable = true;
            
            //給isa的extra_rc設(shè)置數(shù)值
            newisa.extra_rc = RC_HALF;
            //給isa的has_sidetable_rc設(shè)置標(biāo)識(shí)符為YES,表示在散列表中也存儲(chǔ)有數(shù)據(jù)
            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.
        //復(fù)制另一個(gè)半到散列表中
        sidetable_addExtraRC_nolock(RC_HALF);
    }

    if (slowpath(!tryRetain && sideTableLocked)) sidetable_unlock();
    return (id)this;
}
isa存儲(chǔ)情況.png

代碼結(jié)構(gòu):

  1. 判斷如果是小對(duì)象類型,不進(jìn)行retain,直接返回
  2. 判斷如果不是nonpointer,就直接操作散列表
    • 如果是元類就直接返回,元類無(wú)需進(jìn)行引用計(jì)數(shù)的計(jì)算(前面我們分析過,元類不是nonpointer_isa)
    • 如果不是元類,直接操作散列表sidetable
  3. 判斷如果該對(duì)象正在dealloc,不作任何操作直接退出
  4. 對(duì)isa中的extra_rc進(jìn)行+1操作,并且通過carry存儲(chǔ)是否已滿
  5. 如果extra_rc已經(jīng)達(dá)到最大值,數(shù)據(jù)已滿,carry就是YES
  6. 當(dāng)carry為YES,就將extra_rc中的一半取出來(lái)賦值到isa中的extra_rc,另一半拿出來(lái)存儲(chǔ)到sidetable的計(jì)數(shù)表中。并且設(shè)置isa中的has_sidetable_rc為YES,表示散列表中存儲(chǔ)有引用計(jì)數(shù)。

說明:

  • 不是nonpointer_isa就只有散列表存儲(chǔ)引用計(jì)數(shù),這也很容易理解,因?yàn)榉莕onpointer的isa只存儲(chǔ)有類信息,沒有其他信息。無(wú)法存儲(chǔ)引用計(jì)數(shù)
  • nonpointer_isa有兩個(gè)值,一個(gè)是extra_rc,一個(gè)是has_sidetable_rc,分別用來(lái)存儲(chǔ)引用計(jì)數(shù)和是否存儲(chǔ)有sidetable。
  • 如果extra_rc沒有滿,引用計(jì)數(shù)只存儲(chǔ)在extar_rc(arm占有19位)
  • 如果extra_rc已經(jīng)滿了,就需要取出數(shù)據(jù)的一半存儲(chǔ)在sidetable。并且將isa中的has_sidetable_rc設(shè)置為YES(has_sidetable_rc占有兩位)

retain的過程:

  • 先給isa中的extra_rc引用計(jì)數(shù)+1
  • 如果extra_rc溢出,就取出一半放到sideTable中的引用計(jì)數(shù)表中。只留一半在extra_rc中
  • 如果正在dealloc,就直接dealloc不進(jìn)行任何操作

sidetable的認(rèn)識(shí):

源碼:

// RefcountMap disguises its pointers because we 
// don't want the table to act as a root for `leaks`.
//這個(gè)引用計(jì)數(shù)表是對(duì)象作為鍵,引用計(jì)數(shù)作為值來(lái)存儲(chǔ)的
//當(dāng)引用計(jì)數(shù)為0時(shí),會(huì)自動(dòng)將其objc刪除掉
typedef objc::DenseMap<DisguisedPtr<objc_object>,size_t,RefcountMapValuePurgeable> RefcountMap;

// Template parameters.
enum HaveOld { DontHaveOld = false, DoHaveOld = true };
enum HaveNew { DontHaveNew = false, DoHaveNew = true };

//額外的散列表
struct SideTable {
    spinlock_t slock;//自旋鎖,對(duì)于表的使用需要加解鎖
    RefcountMap refcnts;//引用計(jì)數(shù)表,僅在未開啟isa優(yōu)化 或 在isa優(yōu)化情況下isa_t的引用計(jì)數(shù)溢出時(shí)才會(huì)用到
    weak_table_t weak_table;//弱引用表,弱引用計(jì)數(shù)存儲(chǔ)在這里

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

    //可以看到SideTable是不可以析構(gòu)的,
    ~SideTable() {
        _objc_fatal("Do not delete SideTable.");
    }

    //鎖的操作,SideTable的讀取需要進(jìn)行加解鎖
    void lock() { slock.lock(); }
    void unlock() { slock.unlock(); }
    void forceReset() { slock.forceReset(); }

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

    template<HaveOld, HaveNew>
    static void lockTwo(SideTable *lock1, SideTable *lock2);
    template<HaveOld, HaveNew>
    static void unlockTwo(SideTable *lock1, SideTable *lock2);
};

說明:

  • 額外信息表SideTable存儲(chǔ)有引用計(jì)數(shù)表和弱引用表
  • 引用計(jì)數(shù)表僅在未開啟isa優(yōu)化 或 在isa優(yōu)化情況下isa_t的引用計(jì)數(shù)溢出時(shí)才會(huì)用到
  • 這個(gè)引用計(jì)數(shù)表是對(duì)象作為鍵,引用計(jì)數(shù)作為值來(lái)存儲(chǔ)的
  • 當(dāng)一個(gè)對(duì)象被弱引用時(shí),就需要在弱引用表中進(jìn)行存儲(chǔ)
  • 同時(shí)在這里還有一個(gè)自旋鎖,是通過spinlock_t來(lái)實(shí)現(xiàn)的
  • 自旋鎖簡(jiǎn)單來(lái)說會(huì)忙等待,效率高。
  • 加鎖是為了線程安全,防止對(duì)引用計(jì)數(shù)的讀取出現(xiàn)差錯(cuò)。
  • 同時(shí)看到SideTable是不可以刪除的,這個(gè)是系統(tǒng)自己創(chuàng)建的,我們無(wú)法刪除

weak_table_t

源碼:

/**
 * The global weak references table. Stores object ids as keys,
 * and weak_entry_t structs as their values.
 * 全局弱引用表。
 * 將對(duì)象ID存儲(chǔ)為鍵,將weak_entry_t結(jié)構(gòu)體存儲(chǔ)為值
 */
struct weak_table_t {
    weak_entry_t *weak_entries;//是一個(gè)動(dòng)態(tài)數(shù)組,里面存儲(chǔ)了很多的弱引用
    size_t    num_entries;//弱引用的數(shù)量
    uintptr_t mask;//用來(lái)哈希計(jì)算,為總數(shù)-1
    uintptr_t max_hash_displacement;//可能發(fā)生的最大沖突數(shù)
};

說明:

  • 可以看到weak_table_t這是一個(gè)全局的弱引用表,里面存儲(chǔ)有多個(gè)弱引用表
  • 在weak_entries中對(duì)象ID作為鍵,weak_entry_t作為值存儲(chǔ)。

總結(jié):

  • 弱引用表存在于sideTable表中
  • isa中有weakly_refrenced來(lái)判斷是否存在弱引用
  • 弱引用表使用對(duì)象ID作為鍵,弱引用動(dòng)態(tài)數(shù)組作為值存儲(chǔ)

release

通過objc_release() -> release() -> rootRelease() -> rootRelease(bool performDealloc, bool handleUnderflow)查找到是在rootRelease函數(shù)中進(jìn)行了release操作

ALWAYS_INLINE bool 
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)) {//如果不是nonpointer_isa,就直接操作sideTable,進(jìn)行減一
            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
        //進(jìn)行引用計(jì)數(shù)-1操作,即extra_rc-1
        uintptr_t carry;
        newisa.bits = subc(newisa.bits, RC_ONE, 0, &carry);
        //如果此時(shí)extra_rc的值為0了,則走到underflow,
        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:
    // newisa.extra_rc-- underflowed: borrow from side table or deallocate
    // 如果isa中的extra_rc減完之后已經(jīng)為0,就開始從sideTable獲取數(shù)據(jù),或者如果全部為0,就開始deallocate
    // abandon newisa to undo the decrement
    newisa = oldisa;

    //通過has_sidetable_rc判斷散列表中是否存在計(jì)數(shù)
    if (slowpath(newisa.has_sidetable_rc)) {
        if (!handleUnderflow) {
            ClearExclusive(&isa.bits);
            return rootRelease_underflow(performDealloc);
        }

        // Transfer retain count from side table to inline storage.
        //從sideTable轉(zhuǎn)移引用計(jì)數(shù)到extra_rc
        //先上鎖
        if (!sideTableLocked) {
            ClearExclusive(&isa.bits);
            sidetable_lock();
            sideTableLocked = true;
            // Need to start over to avoid a race against 
            // the nonpointer -> raw pointer transition.
            goto retry;
        }

        // Try to remove some retain counts from the side table.
        //取出一半的引用計(jì)數(shù)
        size_t borrowed = sidetable_subExtraRC_nolock(RC_HALF);

        // To avoid races, has_sidetable_rc must remain set 
        // even if the side table count is now zero.
        //即使已經(jīng)為0了,也需要設(shè)置has_sidetable_rc
        if (borrowed > 0) {
            // Side table retain count decreased.
            // Try to add them to the inline count.
            //extra_rc有數(shù)據(jù)后,就再-1
            newisa.extra_rc = borrowed - 1;  // redo the original decrement too,計(jì)數(shù)-1
            bool stored = StoreReleaseExclusive(&isa.bits, 
                                                oldisa.bits, newisa.bits);
            if (!stored) {
                // Inline update failed. 
                // Try it again right now. This prevents livelock on LL/SC 
                // architectures where the side table access itself may have 
                // dropped the reservation.
                isa_t oldisa2 = LoadExclusive(&isa.bits);
                isa_t newisa2 = oldisa2;
                if (newisa2.nonpointer) {
                    uintptr_t overflow;
                    newisa2.bits = 
                        addc(newisa2.bits, RC_ONE * (borrowed-1), 0, &overflow);
                    if (!overflow) {
                        stored = StoreReleaseExclusive(&isa.bits, oldisa2.bits, 
                                                       newisa2.bits);
                    }
                }
            }

            if (!stored) {
                // Inline update failed.
                // Put the retains back in the side table.
                sidetable_addExtraRC_nolock(borrowed);
                goto retry;
            }

            // Decrement successful after borrowing from side table.
            // This decrement cannot be the deallocating decrement - the side 
            // table lock and has_sidetable_rc bit ensure that if everyone 
            // else tried to -release while we worked, the last one would block.
            sidetable_unlock();
            return false;
        }
        else {
            // Side table is empty after all. Fall-through to the dealloc path.
        }
    }

    // Really deallocate.

    //如果沒有就直接dealloc
    if (slowpath(newisa.deallocating)) {
        ClearExclusive(&isa.bits);
        if (sideTableLocked) sidetable_unlock();
        return overrelease_error();
        // does not actually return
    }
    newisa.deallocating = true;
    if (!StoreExclusive(&isa.bits, oldisa.bits, newisa.bits)) goto retry;

    if (slowpath(sideTableLocked)) sidetable_unlock();

    __c11_atomic_thread_fence(__ATOMIC_ACQUIRE);

    if (performDealloc) {
        ((void(*)(objc_object *, SEL))objc_msgSend)(this, @selector(dealloc));
    }
    return true;
}

說明:

  • 過程與retain的剛好相反
  • 先直接將isa中的extra_rc中的數(shù)據(jù)進(jìn)行-1
  • 如果已經(jīng)為0,則從sideTable獲取數(shù)據(jù)
  • 如果sideTable中也沒有數(shù)據(jù),就進(jìn)行dealloc
  • 如果有數(shù)據(jù),就取出一半的數(shù)據(jù)放到extra_rc中,再對(duì)extra_rc進(jìn)行-1

release的過程為:

  • 如果isa中的extra_rc引用計(jì)數(shù)值不為0,就直接減1;
  • 如果值為0,就先從sideTable的引用計(jì)數(shù)獲取值,取出其中的一半存儲(chǔ)到extra_rc中,并繼續(xù)-1.
  • 如果減完之后引用計(jì)數(shù)為0,就開始dealloc。

dealloc

在源碼中通過dealloc -> _objc_rootDealloc -> rootDealloc,在rootDealloc中進(jìn)行真正的dealloc操作

rootDealloc

源碼:

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

    //如果是nonpointer、而且有弱引用,關(guān)聯(lián)對(duì)象、是否有析構(gòu)器,是否有存儲(chǔ)的引用計(jì)數(shù)
    /*
     如果是nonpointer_isa,不會(huì)進(jìn)
     如果不是nonpointer_isa,這幾個(gè)條件有一個(gè)還在,就不會(huì)進(jìn)
     */
    if (fastpath(isa.nonpointer  &&  
                 !isa.weakly_referenced  &&  
                 !isa.has_assoc  &&  
                 !isa.has_cxx_dtor  &&  
                 !isa.has_sidetable_rc))
    {
        assert(!sidetable_present());
        free(this);
    }
    //如果非nonpointer_isa或者是nonpointer_isa,且存在那幾個(gè)條件就需要銷毀一些東西
    else {
        object_dispose((id)this);
    }
}

說明:

  • 如果是小對(duì)象類型無(wú)需操作
  • 如果是nonpointer_isa,但是不存在弱引用表、關(guān)聯(lián)對(duì)象、析構(gòu)器、額外數(shù)據(jù)表sidetable,就可以直接刪掉
  • 如果是非nonpointer_isa,或者是nonpointer_isa,但是存在弱引用表、關(guān)聯(lián)對(duì)象、析構(gòu)器、額外數(shù)據(jù)表sidetable,就需要先刪除這些東西。

object_dispose

源碼:

id 
object_dispose(id obj)
{
    if (!obj) return nil;

    //先破壞對(duì)象
    objc_destructInstance(obj);
    //再清除空間
    free(obj);

    return nil;
}

說明:

  • 這里只是調(diào)用objc_destructInstance進(jìn)行銷毀對(duì)象,之后再清除對(duì)象的空間

objc_destructInstance

源碼:

/***********************************************************************
* objc_destructInstance
* Destroys an instance without freeing memory. 這里只銷毀實(shí)例,不在這里清除內(nèi)存
* Calls C++ destructors.調(diào)用C++析構(gòu)器
* Calls ARC ivar cleanup.調(diào)用ARC變量清除
* Removes associative references.移除關(guān)聯(lián)對(duì)象
* Returns `obj`. Does nothing if `obj` is nil.將返回obj,如果obj是nil,將不進(jìn)行任何操作
**********************************************************************/
void *objc_destructInstance(id obj) 
{
    if (obj) {
        // Read all of the flags at once for performance.
        bool cxx = obj->hasCxxDtor();
        bool assoc = obj->hasAssociatedObjects();

        // This order is important.
        //這個(gè)順序很重要。
        /*
         1、先進(jìn)行C++析構(gòu)函數(shù)調(diào)用
         2、移除關(guān)聯(lián)對(duì)象
         3、弱引用
         4、sideTable
         */
        /*
         如果是nonapoint_isa,,不移除弱引用
         */
        if (cxx) object_cxxDestruct(obj);//C++析構(gòu)函數(shù)
        if (assoc) _object_remove_assocations(obj);//刪除關(guān)聯(lián)對(duì)象
        obj->clearDeallocating();
    }

    return obj;
}

clearDeallocating

源碼:

/*
 刪除has_sidetable_rc和extra_rc
 */
inline void 
objc_object::clearDeallocating()
{
    //如果不是nonpointer,清除has_sidetable_rc和extra_rc
    if (slowpath(!isa.nonpointer)) {
        // Slow path for raw pointer isa.
        sidetable_clearDeallocating();
    }
    //判斷是否存在弱引用和額外的引用計(jì)數(shù)
    else if (slowpath(isa.weakly_referenced  ||  isa.has_sidetable_rc)) {
        // Slow path for non-pointer isa with weak refs and/or side table data.
        clearDeallocating_slow();
    }

    assert(!sidetable_present());
}

說明:

  • 這里只銷毀,不清除內(nèi)存
  • 一個(gè)是注意銷毀的內(nèi)容包括C++析構(gòu)函數(shù)、關(guān)聯(lián)對(duì)象、弱引用、sideTable。
  • 第二個(gè)是注意銷毀的順序?yàn)镃++析構(gòu)函數(shù)、關(guān)聯(lián)對(duì)象、弱引用、sideTable。

總結(jié):

  • dealloc時(shí)需要先清除C++析構(gòu)函數(shù)、關(guān)聯(lián)對(duì)象、弱引用、sideTable,通過isa來(lái)判斷是否需要清除
  • 清除的順序?yàn)镃++析構(gòu)函數(shù)、關(guān)聯(lián)對(duì)象、弱引用、sideTable

retainCount

源碼:

inline uintptr_t 
objc_object::rootRetainCount()
{
    if (isTaggedPointer()) return (uintptr_t)this;//小對(duì)象類型不用處理

    sidetable_lock();
    isa_t bits = __c11_atomic_load((_Atomic uintptr_t *)&isa.bits, __ATOMIC_RELAXED);
    //如果是nonpointer,取出extra_rc和sidetable中的引用計(jì)數(shù)加在一起取出來(lái)
    if (bits.nonpointer) {
        uintptr_t rc = bits.extra_rc;
        if (bits.has_sidetable_rc) {
            rc += sidetable_getExtraRC_nolock();
        }
        sidetable_unlock();
        return rc;
    }

    sidetable_unlock();
    return sidetable_retainCount();
}

說明:

  • extra_rc和sidetable中的引用計(jì)數(shù)加在一起就是這個(gè)對(duì)象的引用計(jì)數(shù)值

看一個(gè)面試題打印什么?

- (void)test2{
    NSLog(@"%ld",CFGetRetainCount((__bridge CFTypeRef)[NSObject alloc]));
}

說明:

  • 查看運(yùn)行結(jié)果打印的是1。
  • 此處我們并沒有將這個(gè)對(duì)象附給任何變量,但是就已經(jīng)引用計(jì)數(shù)+1了。

初始化isa源碼

inline void 
objc_object::initIsa(Class cls, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor)
{ 
    ASSERT(!isTaggedPointer()); 
    
    isa_t newisa(0);

    if (!nonpointer) {
        newisa.setClass(cls, this);
    } else {
        ASSERT(!DisableNonpointerIsa);
        ASSERT(!cls->instancesRequireRawIsa());


#if SUPPORT_INDEXED_ISA
        ASSERT(cls->classArrayIndex() > 0);
        newisa.bits = ISA_INDEX_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
        newisa.bits = ISA_MAGIC_VALUE;
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE
#   if ISA_HAS_CXX_DTOR_BIT
        newisa.has_cxx_dtor = hasCxxDtor;
#   endif
        newisa.setClass(cls, this);
#endif
        newisa.extra_rc = 1;
    }

    // This write must be performed in a single store in some cases
    // (for example when realizing a class because other threads
    // may simultaneously try to use the class).
    // fixme use atomics here to guarantee single-store and to
    // guarantee memory order w.r.t. the class index table
    // ...but not too atomic because we don't want to hurt instantiation
    isa = newisa;
}

說明:

  • 其他的以前均已經(jīng)分析過,這里單看newisa.extra_rc = 1;這一條語(yǔ)句,在初始化isa的時(shí)候就已經(jīng)給extra_rc設(shè)置為1。
  • 這也就是當(dāng)alloc一個(gè)對(duì)象之后引用計(jì)數(shù)就為1.

總結(jié):

  • retainCount得到的值是isa中的extra_rc中的值加上sideTable中的引用計(jì)數(shù)的值
  • 當(dāng)alloc創(chuàng)建出對(duì)象時(shí),默認(rèn)引用計(jì)數(shù)為1
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容