isa在對象中的做用

isa是什麼

isa 是存在對象中類型是isa_t的聯合體c++

//去掉了一些多餘的代碼
union isa_t {
    Class cls;
    uintptr_t bits;
    struct {
        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
    };
};
複製代碼

nonpointer

nonpointer表明是不是純指針bash

  • 0 表明純指針
  • 1 表明不止是類對象地址,isa 中包含了類信息、對象的引用計數等 #####has_assoc 關聯對象標誌位 #####has_cxx_dtor 該對象是否有 C++ 或者 Objc 的析構器,若是有析構函數,則須要作析構邏輯, 若是沒有,則能夠更快的釋放對象 #####shiftcls 存儲類指針的值。開啓指針優化的狀況下,在 arm64 架構中有 33 位用來存儲類指針 #####magic 用於調試器判斷當前對象是真的對象仍是沒有初始化的空間 #####weakly_referenced 存儲對象是否被指向或者曾經指向一個 ARC 的弱變量, 沒有弱引用的對象能夠更快釋放。 #####deallocating 標誌對象是否正在釋放內存 #####has_sidetable_rc 當對象引用技術大於 10 時,則須要借用該變量存儲進位 #####extra_rc 當表示該對象的引用計數值,其實是引用計數值減 1, 例如,若是對象的引用計數爲 10,那麼 extra_rc 爲 9。若是引用計數大於 10, 則須要使用到下面的 has_sidetable_rc

isa 初始化

核心代碼架構

objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    if (!nonpointer) {
        //若是是純指針,直接設置到cls
        isa.cls = cls;
    } else {
        isa_t newisa(0);

        //arm64 # define ISA_MAGIC_VALUE 0x000001a000000001ULL
        //ISA_MAGIC_VALUE  0b0000000000000000000000011010000000000000000000000000000000000001
        /* 
            ISA_MAGIC_VALUE 至關於 
            newisa.nonpointer = 0b1;
            newisa.magic = 0b011010;
        */
        newisa.bits = ISA_MAGIC_VALUE;  //標記空間被初始化
        // isa.magic is part of ISA_MAGIC_VALUE
        // isa.nonpointer is part of ISA_MAGIC_VALUE

        //has_cxx_dtor 標記是否存在c++ 析構函數
        newisa.has_cxx_dtor = hasCxxDtor;

        //shiftcls 保存指針的有效信息
        /*
        這裏爲何要 >>3 ?
        主要緣由是用於指針中無用的後三位清除減少內存的消耗
        指針要按照 8字節對齊,其指針後三位是沒有意義的0
        全部指針地址結尾都是 8 或者 0 ( 如 0x0000000100b350f0)
        */
        newisa.shiftcls = (uintptr_t)cls >> 3;

        isa = newisa;
    }
}
複製代碼

####isa 和 superclass 的指向圖 ide

isa流程圖.png

驗證這幅圖的正確性

運行環境 x86_64函數

1. 先檢查實例對象內存

// 檢查 object 對象內存,並格式化打印 4個內存空間
(lldb) x/4gx object
0x101120ba0: 0x001d800100001131 0x0000000000000000
0x101120bb0: 0x0000000000000002 0x00007fff9e64e898

// 冒號左邊的表示地址,右邊的表示內容
(lldb) po 0x101120ba0
<LGPerson: 0x101120ba0>

// 第一個存儲的內容 0x001d800100001131 就是isa
// 經過 & ISA_MASK 運算能夠獲得父類對象地址
// 當前環境下 ISA_MASK
//# define ISA_MASK 0x00007ffffffffff8ULL
(lldb) p/x 0x001d800100001131 & 0x00007ffffffffff8ULL
(unsigned long long) $25 = 0x0000000100001130
(lldb) po 0x0000000100001130
LGPerson

複製代碼

2. 檢查類對象內存

//上一步操做 獲得 0x0000000100001130 就是類對象地址
// 檢查父類對象內存
(lldb) x/4gx 0x0000000100001130
0x100001130: 0x001d800100001109 0x0000000100b35140
0x100001140: 0x0000000100f6df70 0x0000000400000007

//結構和實例對象一致
//第一個就是isa ,這裏的isa指向的是元類對象
(lldb) p/x 0x001d800100001109 & 0x00007ffffffffff8ULL
(unsigned long long) $31 = 0x0000000100001108
(lldb) po 0x0000000100001108
LGPerson

//第二個是 superclass (從這裏看到了繼承關係),實例對象第二個空間是空的
//當前類是繼承與 NSObject的,就到了途中的 Root Class
//只有isa 通過了 & ISA_MASK處理,superclass 存儲的就是純指針
(lldb) po 0x0000000100b35140
NSObject

複製代碼

3. 檢查元類對象內存

//上一步操做 獲得 0x0000000100001108 就是元類對象地址
// 檢查元類對象內存
(lldb) x/4gx 0x0000000100001108
0x100001108: 0x001d800100b350f1 0x0000000100b350f0
0x100001118: 0x000000010122d320 0x0000000300000007

//結構與類對象一致
//第一個就是isa ,這裏的isa指向的是元類對象
(lldb) p/x 0x001d800100b350f1 & 0x00007ffffffffff8ULL
(unsigned long long) $34 = 0x0000000100b350f0
(lldb) po 0x0000000100b350f0
NSObject

//第二個是 superclass
//元類的繼承與類是差很少的,繼承自根元類(Meta Root Class)
(lldb) po 0x0000000100b350f0
NSObject

複製代碼

4. 檢查根元類對象內存

//上一步操做 獲得 0x0000000100b350f0 就是根元類對象地址
// 檢查根元類對象內存
(lldb) x/4gx 0x0000000100b350f0
0x100b350f0: 0x001d800100b350f1 0x0000000100b35140
0x100b35100: 0x0000000100f6e320 0x0000000400000007

//第一個就是isa ,這裏的isa指向的本身 
(lldb) p/x 0x001d800100b350f1 & 0x00007ffffffffff8ULL
(unsigned long long) $38 = 0x0000000100b350f0
(lldb) po 0x0000000100b350f0
NSObject

//第二個是 superclass
//根據以前檢查 0x0000000100b35140 是NSObject (基類)
//根元類 的superclas指向了基類,也就是繼承自基類
(lldb) po 0x0000000100b35140
NSObject
複製代碼

至此isa 以及superclass ,以及完成了閉環。 圖上的指向驗證完成優化

相關文章
相關標籤/搜索