iOS isa 引用計數管理

iOS isa 引用計數管理

之前文章提得到過在 arm64 之后,蘋果對isa指針進行了優化,采用 共用體的方式,nopointer 的方式來管理 isa,也就是說,isa 指針不僅僅只存放地址,也存放著引用計數相關的東西,我們來看源碼


   uintptr_t nonpointer        : 1;                                       \
      uintptr_t has_assoc         : 1;                                       \
      uintptr_t has_cxx_dtor      : 1;                                       \
      uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
      uintptr_t magic             : 6;                                       \
      uintptr_t weakly_referenced : 1;                                       \
      uintptr_t deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19

isa 指針的定義大概是這樣的


1. nonpointer,0代表普通的指針,存儲著class ,meta-class 對象的內存地址,1代表優化過,使用位域存儲更多的信息。
2. has_cxx_dtor : 是否有 C++ 的析構函數,如果沒有,釋放的時候回更快
3. shiftcls,存儲著 class ,meta-class 對象的內存地址信息。
4. magic:用于在調試時分辨對象是否未完成初始化
5. weakly_referenced:是否有被弱引用指向過,如果沒有,釋放時候會更快
6. deallocating 對象是否正在釋放
7. extra_rc 里面存儲的值是引用計數減一
8. has_sidetable_rc:引用計數是否過大無法存儲在 isa 中,如果為1,那么引用計數會存儲在一個叫 SideTable 的類的屬性中。
9. has_assoc : 是否有設置過關聯對象,如果沒有,釋放會更快



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

我們來看下 SideTable 這個類,RefcountMap 存儲著引用計數,是個散列表,根據一個 key 就可以找到對應的 value,

objc_object::rootRetainCount()
{
    if (isTaggedPointer()) return (uintptr_t)this;

    sidetable_lock();
    isa_t bits = LoadExclusive(&isa.bits);
    ClearExclusive(&isa.bits);
    if (bits.nonpointer) {
        uintptr_t rc = 1 + bits.extra_rc;
        if (bits.has_sidetable_rc) {
            rc += sidetable_getExtraRC_nolock();
        }
        sidetable_unlock();
        return rc;
    }

    sidetable_unlock();
    return sidetable_retainCount();
}


objc_object::sidetable_getExtraRC_nolock()
{
    assert(isa.nonpointer);
    SideTable& table = SideTables()[this];
    RefcountMap::iterator it = table.refcnts.find(this);
    if (it == table.refcnts.end()) return 0;
    else return it->second >> SIDE_TABLE_RC_SHIFT;
}


retainCount

這個源碼是獲取 retainCount , 可以看到,如果是 tagged pointer 類型的,那么直接返回,什么事tagged pointer ,我之前文章也有說過,接下來,去拿到 isa ,isa.bits,就代表拿到 isa,首先看下是否為 非指針類型也就是優化過的 isa,如果是的話,那么久直接將 extra_rc + 1,也就是引用計數加一,如果 bits.has_sidetable_rc 為1,那么他的引用計數是存儲在 SideTable 里面的,不是存儲在 isa 中,從 方法中可以看到,是先從 SideTables里面穿進去一個 key,拿到 SideTable ,然后又拿到這個SideTable 的 refcnts,也就是那個存放引用計數的散列表,然后再出入一個 key ,拿到一個遍歷器,然后進行位運算。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容