iOS-OC對(duì)象— isa指針分析探究

前言:isa 是個(gè)很神奇的、很強(qiáng)大的、很低調(diào)的角色,她風(fēng)里來雨里去,在iOS開發(fā)的過程中曾經(jīng)多少次出現(xiàn)在我們的世界里,悄無聲息、無怨無悔的為我們提供各種各樣的服務(wù)!假如你知道NSObject,那么你就一定要知道isa,可以說,她是一個(gè)對(duì)象的靈魂,如果沒有她,一切都將失去了顏色......

一、從對(duì)象的alloc探索isa

PS:友情鏈接

《OC對(duì)象原理探究(上)——對(duì)象的alloc》

《OC對(duì)象原理探究(下)—— 聯(lián)合體(共用體)與位域》

1、isa和對(duì)象alloc的關(guān)系

  • 前面講過alloc的過程分析,涉及到對(duì)象的創(chuàng)建和關(guān)聯(lián)部分,如下源碼:
 if (!zone && fast) {
        obj->initInstanceIsa(cls, hasCxxDtor);
    } else {
        // Use raw pointer isa on the assumption that they might be
        // doing something weird with the zone or RR.
        obj->initIsa(cls);
    }

涉及到對(duì)象的內(nèi)存分配部分,追蹤核心代碼 obj->initIsa(cls)。

...
union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    uintptr_t bits;

private:
  
    Class cls;

#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };

2、ISA_BITFIELD的定義

我們?cè)诜治隽薕C對(duì)象的本質(zhì)之后,知道了對(duì)象的內(nèi)部,都至少存在一個(gè)isa成員變量,isa占用的空間大小為8字節(jié),也就是8x8=64位。

如果我們把這些空間都用于存放指針,那么造成的空間浪費(fèi)是巨大的。而類中除了指針,還可能有其他的東西需要進(jìn)行存儲(chǔ),如果能夠?qū)@8字節(jié)空間進(jìn)行一系列優(yōu)化,就可以節(jié)省很多的內(nèi)存開銷。

  • 類中與存儲(chǔ)相關(guān)的一個(gè)類型就是nonPointerIsa,涉及到存儲(chǔ)的變量信息主要有以下: ① 是否正在釋放? ② 引用計(jì)數(shù) ③ weak ④ map ⑤ 關(guān)聯(lián)對(duì)象 ⑥ 析構(gòu)函數(shù) 存儲(chǔ)空間的釋放——>內(nèi)部是C/C++的釋放
  • 查看nonPointerIsa的相關(guān)定義:
# if __arm64__
#     define ISA_MASK        0x0000000ffffffff8ULL
#     define ISA_MAGIC_MASK  0x000003f000000001ULL
#     define ISA_MAGIC_VALUE 0x000001a000000001ULL
#     define ISA_HAS_CXX_DTOR_BIT 1
#     define ISA_BITFIELD 
        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 unused            : 1;                                       \
        uintptr_t has_sidetable_rc  : 1;                                       \
        uintptr_t extra_rc          : 19
#     define RC_ONE   (1ULL<<45)
#     define RC_HALF  (1ULL<<18)
#   endif

在以上isa.h中定義了arm64架構(gòu)下isa的類型,其中我們關(guān)注ISA_BITFIELD的結(jié)構(gòu):

可以看到,ISA_BITFIELD被定義為位域的結(jié)構(gòu)。

3、ISA_BITFIELD中不同位域的作用

① nonpointer:表示是否對(duì) isa 指針開啟指針優(yōu)化 0:純isa指針,1:不止是類對(duì)象地址,isa 中包含了類信息、對(duì)象的引用計(jì)數(shù)等

② has_assoc:關(guān)聯(lián)對(duì)象標(biāo)志位,0沒有,1存在

③ has_cxx_dtor:該對(duì)象是否有 C++ 或者 Objc 的析構(gòu)器,如果有析構(gòu)函數(shù),則需要做析構(gòu)邏輯, 如果沒有,則可以更快的釋放對(duì)象。

④ shiftcls: 存儲(chǔ)類指針的值。開啟指針優(yōu)化的情況下,在 arm64 架構(gòu)中有 33 位用來存儲(chǔ)類指針。

⑤ magic:用于調(diào)試器判斷當(dāng)前對(duì)象是真的對(duì)象還是沒有初始化的空間

⑥ weakly_referenced:志對(duì)象是否被指向或者曾經(jīng)指向一個(gè) ARC 的弱變量,沒有弱引用的對(duì)象可以更快釋放。 deallocating:標(biāo)志對(duì)象是否正在釋放內(nèi)存

⑦ has_sidetable_rc:當(dāng)對(duì)象引用技術(shù)大于 10 時(shí),則需要借用該變量存儲(chǔ)進(jìn)位

extra_rc:當(dāng)表示該對(duì)象的引用計(jì)數(shù)值,實(shí)際上是引用計(jì)數(shù)值減 1, 例如,如果對(duì)象的引用計(jì)數(shù)為 10,那么 extra_rc 為 9。如果引用計(jì)數(shù)大于 10, 則需要使用到下面的 has_sidetable_rc。

4、isa和class的關(guān)系

imageng

通過查看YTPerson類的內(nèi)存,

① 獲取YTPerson對(duì)象地址:$5 = 0x00000001000080e8 YTPerson

② 獲取到isa的地址 0x001d8001000080e9

③ 用isa的地址和ISA_MASK進(jìn)行&運(yùn)算,得到計(jì)算后的地址:$6 = 0x00000001000080e8

④ 對(duì)比5和6的地址,發(fā)現(xiàn)關(guān)系:對(duì)象的地址 = isa的地址 & ISA_MASK

二、isa和class賦值過程

1、從class拿類的核心內(nèi)容

  • 從前面的分析,我們得知,isa的類核心信息,都存在uintptr_t shiftcls之中,于是我們可以根據(jù)一個(gè)類的地址,通過位移運(yùn)算,得到cls的實(shí)際地址值。
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_HAS_CXX_DTOR_BIT 1
#   define ISA_BITFIELD                                                        \
      uintptr_t nonpointer        : 1;                                         \
      uintptr_t has_assoc         : 1;                                         \
      uintptr_t has_cxx_dtor      : 1;                                         \
      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
      uintptr_t magic             : 6;                                         \
      uintptr_t weakly_referenced : 1;                                         \
      uintptr_t unused            : 1;                                         \
      uintptr_t has_sidetable_rc  : 1;                                         \
      uintptr_t extra_rc          : 8
#   define RC_ONE   (1ULL<<56)
#   define RC_HALF  (1ULL<<7)

2、通過class獲取isa的值

image99png
  • 過程分析 ① 獲取YTPerson對(duì)象p的地址:0x001d8001000080e9

② 將p的地址左移 3 位,得到$8 = 0x0003b0002000101d

③ 將8的地址右移20位,得到9 = 0x0002000101d00000

④ 將9的地址左移17位,得到10 = 0x00000001000080e8

⑤ 查看YTPerson的地址11 = 0x00000001000080e8 =10

文末總結(jié):
1、一個(gè)類的核心信息,實(shí)際上存在于ISA_BITFIELD中,由于位域公用一片內(nèi)存的特點(diǎn),可以根據(jù)地址的偏移,去拿到存儲(chǔ)類信息的位域 shiftcls 的地址,也即是示例中YTPerson的isa地址。
2、類中的聯(lián)合體位域的存儲(chǔ)結(jié)構(gòu),優(yōu)化了存儲(chǔ)空間,提升了運(yùn)算能力,對(duì)有限的內(nèi)存空間下的軟件開發(fā),有著極其重要的意義!

青山不改,綠水常流。謝謝大家!

?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過簡信或評(píng)論聯(lián)系作者。

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

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