OC對象原理(二)— isa指針詳解

OC是一門面向?qū)ο蟮恼Z言蛋褥,上篇文章我們講解了對象創(chuàng)建alloc的流程吮成,知道了每個(gè)對象都有一個(gè)isa指針频丘,那么我們接著上篇文章詳細(xì)講解一下isa初始化過程、isa內(nèi)部結(jié)構(gòu)和isa指向分析俱病。

isa的初始化

通過上篇文章知道isa的初始化都會(huì)調(diào)用initisa方法官疲,如下:

inline void 
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    assert(!isTaggedPointer()); 
    
    if (!nonpointer) {
        isa.cls = cls;
    } else {
        assert(!DisableNonpointerIsa);
        assert(!cls->instancesRequireRawIsa());

        isa_t newisa(0); //創(chuàng)建isa

#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
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.shiftcls = (uintptr_t)cls >> 3;
#endif

        // 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;
    }
}
  • isTaggedPointer
    taggedPointer是蘋果用來優(yōu)化一些小的對象的杂曲,把對象的值存在了對象指針里,優(yōu)化了內(nèi)存和讀取速度袁余,詳細(xì)請看 文章
  • nonpointer
    isa有兩種類型咱揍,一種是純指針類型颖榜,一種是除了內(nèi)存地址,還包含其他一些信息煤裙,就是NON_POINTER_ISA類型的isa掩完。如果是純指針類型的直接賦值cls。如果不是純指針類型需要初始化一個(gè)新的isa對象硼砰,isa初始化的時(shí)候給bits且蓬、has_cxx_dtorshiftcls賦值题翰,shiftcls存儲(chǔ)的是cls信息恶阴,isa也是在這里關(guān)聯(lián)到類的。
  • SUPPORT_INDEXED_ISA
    表示 isa_t 中存放的 Class 信息是 Class 的地址豹障,還是一個(gè)索引(根據(jù)該索引可在類信息表中查找該類結(jié)構(gòu)地址)冯事。經(jīng)測試,iOS 設(shè)備上 SUPPORT_INDEXED_ISA 是 0血公。

isa的結(jié)構(gòu)

//isa結(jié)構(gòu)
union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

可以看出isa是一個(gè)聯(lián)合體昵仅,包含了clsbits,因?yàn)槭锹?lián)合體累魔,clsbits不會(huì)被同時(shí)賦值摔笤。cls存儲(chǔ)的是對象的類信息,即!nonpointer直接設(shè)置cls垦写。bits則是一個(gè)位域ISA_BITFIELD吕世,ISA_BITFIELD結(jié)構(gòu)如下:

# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
#   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 deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19
#   define RC_ONE   (1ULL<<45)
#   define RC_HALF  (1ULL<<18)

# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   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 deallocating      : 1;                                         \
      uintptr_t has_sidetable_rc  : 1;                                         \
      uintptr_t extra_rc          : 8
#   define RC_ONE   (1ULL<<56)
#   define RC_HALF  (1ULL<<7)

ISA_BITFIELD的結(jié)構(gòu)和系統(tǒng)有關(guān),我們調(diào)試的環(huán)境是x86梯澜。ISA_BITFIELD的結(jié)構(gòu)也就代表了isa的內(nèi)部結(jié)構(gòu)分布寞冯。

  • ISA_MASK:
    掩碼。作用通俗的講就是顯示該顯示的內(nèi)容晚伙。
  • nonpointer:
    表示是否對 isa 指針開啟指針優(yōu)化 0:純isa指針吮龄,1:不止是類對象地址,isa 中包含了類信息、對象的引用計(jì)數(shù)等咆疗。
  • has_assoc:
    關(guān)聯(lián)對象標(biāo)志位漓帚,0沒有,1存在午磁。
  • has_cxx_dtor:
    該對象是否有 C++ 或者 Objc 的析構(gòu)器,如果有析構(gòu)函數(shù),則需要做析構(gòu)邏輯, 如果沒有,則可以更快的釋放對象尝抖。
  • shiftcls:
    存儲(chǔ)類指針的值毡们。開啟指針優(yōu)化的情況下,在 arm64 架構(gòu)中有 33 位用來存儲(chǔ)類指針昧辽。x86下是44位衙熔。
  • magic:
    用于調(diào)試器判斷當(dāng)前對象是真的對象還是沒有初始化的空間。
  • weakly_referenced:
    標(biāo)志對象是否被指向或者曾經(jīng)指向一個(gè) ARC 的弱變量搅荞,沒有弱引用的對象可以更快釋放红氯。
  • deallocating:
    標(biāo)志對象是否正在釋放內(nèi)存。
  • has_sidetable_rc:
    當(dāng)對象引用計(jì)數(shù)大于 10 時(shí)咕痛,則需要借用該變量存儲(chǔ)進(jìn)位痢甘。
  • extra_rc:
    表示該對象的引用計(jì)數(shù)值,實(shí)際上是引用計(jì)數(shù)值減 1茉贡, 例如塞栅,如果對象的引用計(jì)數(shù)為 10,那么 extra_rc 為 9腔丧。如果引用計(jì)數(shù)大于 10放椰, 則需要使用到上面的 has_sidetable_rc
    通過isa的結(jié)構(gòu)信息愉粤,我們也了解到了isa里主要存儲(chǔ)了哪些對象信息庄敛。
    驗(yàn)證shiftcls

x/4gx十六進(jìn)制輸出對象內(nèi)存前四個(gè)8字節(jié)內(nèi)存,4代表前4個(gè)科汗。
p/t二進(jìn)制輸出藻烤。
p/d十進(jìn)制輸出。
p/o八進(jìn)制輸出头滔。
p/x十六進(jìn)制輸出怖亭。
>>3<<3 先右移三位,再左移三位坤检。相當(dāng)于把最右邊三位刪除兴猩,變?yōu)?。

從上圖可以看出person對象的類信息存儲(chǔ)在了isa的4->47位內(nèi)存中早歇,即shiftcls倾芝。

isa的指向分析

其實(shí)object_getClass方法是通過掩碼ISA_MASK來獲取對象的類信息的。

//object_getClass獲取對象類信息箭跳,最終會(huì)進(jìn)入到這里
inline Class 
objc_object::ISA() 
{
    assert(!isTaggedPointer()); 
#if SUPPORT_INDEXED_ISA
    if (isa.nonpointer) {
        uintptr_t slot = isa.indexcls;
        return classForIndex((unsigned)slot);
    }
    return (Class)isa.bits;
#else
    //通過掩碼獲取isa的類信息
    return (Class)(isa.bits & ISA_MASK);
#endif
}

我們也可以通過ISA_MASK追蹤一下isa的指向晨另。
首先,我們創(chuàng)建LGPersonLGTeacher兩個(gè)類谱姓,其中LGTeacher繼承與LGPerson借尿,LGPerson繼承與NSObject

創(chuàng)建類
創(chuàng)建LGTeacher對象,打斷點(diǎn)路翻。
斷點(diǎn)
isa指向流程分析
isa指向分析

isa的指向和superclass指向流程圖
isa&superClass指向圖

總結(jié)

  • isa在初始化的時(shí)候關(guān)聯(lián)到類狈癞。
  • isa本身是一個(gè)聯(lián)合體;nonpointer類型的isa包含了一個(gè)位域茂契,除了分配類信息外蝶桶,還有一些其他的對象信息;位域的內(nèi)存分配和環(huán)境有關(guān)掉冶。
  • isa的指向:實(shí)例對象→類→類的元類→NSObject的元類→NSObject的元類莫瞬。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市郭蕉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌喂江,老刑警劉巖召锈,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異获询,居然都是意外死亡涨岁,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門吉嚣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來梢薪,“玉大人,你說我怎么就攤上這事尝哆”玻” “怎么了?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵秋泄,是天一觀的道長琐馆。 經(jīng)常有香客問我,道長恒序,這世上最難降的妖魔是什么瘦麸? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮歧胁,結(jié)果婚禮上滋饲,老公的妹妹穿的比我還像新娘。我一直安慰自己喊巍,他們只是感情好屠缭,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著崭参,像睡著了一般勿她。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上阵翎,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天逢并,我揣著相機(jī)與錄音之剧,去河邊找鬼。 笑死砍聊,一個(gè)胖子當(dāng)著我的面吹牛背稼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播玻蝌,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼蟹肘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了俯树?” 一聲冷哼從身側(cè)響起帘腹,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎许饿,沒想到半個(gè)月后阳欲,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡陋率,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年球化,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瓦糟。...
    茶點(diǎn)故事閱讀 38,566評論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡筒愚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出菩浙,到底是詐尸還是另有隱情巢掺,我是刑警寧澤,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布劲蜻,位于F島的核電站址遇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏斋竞。R本人自食惡果不足惜倔约,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望坝初。 院中可真熱鬧浸剩,春花似錦、人聲如沸鳄袍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拗小。三九已至重罪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剿配。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工搅幅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人呼胚。 一個(gè)月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓茄唐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蝇更。 傳聞我的和親對象是個(gè)殘疾皇子沪编,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評論 2 348

推薦閱讀更多精彩內(nèi)容