cache_t的探究

前言

今天我們要探究的cache_t在之前的類的結(jié)構(gòu)分析中看到過(guò)沾谓,在objc_class中存在一個(gè)cache_t類型的成員cache破喻,cache顧名思義緩存职祷,那存的是什么呢盖灸?

cache存的是什么

首先我們看一下cache_t的源碼實(shí)現(xiàn):

struct cache_t {
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
    //macOS蚁鳖、模擬器
    explicit_atomic<struct bucket_t *> _buckets;
    explicit_atomic<mask_t> _mask;
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
    //真機(jī) 64位
    explicit_atomic<uintptr_t> _maskAndBuckets;
    mask_t _mask_unused;
    
    // How much the mask is shifted by.
    static constexpr uintptr_t maskShift = 48;
    
    // Additional bits after the mask which must be zero. msgSend
    // takes advantage of these additional bits to construct the value
    // `mask << 4` from `_maskAndBuckets` in a single instruction.
    static constexpr uintptr_t maskZeroBits = 4;
    
    // The largest mask value we can store.
    static constexpr uintptr_t maxMask = ((uintptr_t)1 << (64 - maskShift)) - 1;
    
    // The mask applied to `_maskAndBuckets` to retrieve the buckets pointer.
    static constexpr uintptr_t bucketsMask = ((uintptr_t)1 << (maskShift - maskZeroBits)) - 1;
    
    // Ensure we have enough bits for the buckets pointer.
    static_assert(bucketsMask >= MACH_VM_MAX_ADDRESS, "Bucket field doesn't have enough bits for arbitrary pointers.");
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_LOW_4
    //真機(jī) 非64位
    // _maskAndBuckets stores the mask shift in the low 4 bits, and
    // the buckets pointer in the remainder of the value. The mask
    // shift is the value where (0xffff >> shift) produces the correct
    // mask. This is equal to 16 - log2(cache_size).
    explicit_atomic<uintptr_t> _maskAndBuckets;
    mask_t _mask_unused;

    static constexpr uintptr_t maskBits = 4;
    static constexpr uintptr_t maskMask = (1 << maskBits) - 1;
    static constexpr uintptr_t bucketsMask = ~maskMask;
#else
#error Unknown cache mask storage type.
#endif
    
#if __LP64__
    uint16_t _flags;
#endif
    uint16_t _occupied;
//部分代碼省略
...
}

這里進(jìn)行了一個(gè)架構(gòu)的判斷:
1、CACHE_MASK_STORAGE_OUTLINED表示macOS模擬器
2赁炎、CACHE_MASK_STORAGE_HIGH_16表示64位的真機(jī)
3醉箕、CACHE_MASK_STORAGE_LOW_4表示非64位的真機(jī)

我們可以看到它們都有一個(gè)explicit_atmic(顯示原子性),使用這個(gè)主要是確保增刪改查時(shí)的安全性徙垫,而模擬器中的_buckets_mask真機(jī)中它們合并成了_maskAndBuckets讥裤,這樣做的目的是為了節(jié)省內(nèi)存,讀取方便姻报。

bucket的意思己英,哪里面裝的是什么呢?這里我們進(jìn)入bucket_t看一下:

struct bucket_t {
private:
    // IMP-first is better for arm64e ptrauth and no worse for arm64.
    // SEL-first is better for armv7* and i386 and x86_64.
#if __arm64__
    explicit_atomic<uintptr_t> _imp;
    explicit_atomic<SEL> _sel;
#else
    explicit_atomic<SEL> _sel;
    explicit_atomic<uintptr_t> _imp;
#endif
//部分代碼省略
...
}

我們可以看到里面裝的是selimp吴旋,同時(shí)這里也進(jìn)行了架構(gòu)的判斷:分為真機(jī)非真機(jī)损肛,區(qū)別在于selimp的順序不同。

總結(jié)
cache中存儲(chǔ)的是sel-imp

cache中查找sel-imp

既然cache_t中存的是sel-imp邮府,哪又是如何查找的呢荧关?

通過(guò)源碼查找

首先我們定義一個(gè)LGPerson類,聲明了兩個(gè)屬性以及5個(gè)方法

@interface LGPerson : NSObject

@property (nonatomic, copy) NSString *lgName;
@property (nonatomic, strong) NSString *nickName;

- (void)sayHello;

- (void)sayCode;

- (void)sayMaster;

- (void)sayNB;

+ (void)sayHappy;

@end

main函數(shù)中執(zhí)行如下代碼褂傀,并在執(zhí)行第一個(gè)方法處打個(gè)斷點(diǎn):

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        LGPerson *p  = [LGPerson alloc];
        Class pClass = [LGPerson class];
//        p.lgName     = @"Cooci";
//        p.nickName   = @"KC";
        // 緩存一次方法 sayHello
        // 4
        [p sayHello];
        [p sayCode];
        [p sayMaster];
//        [p sayNB];


        NSLog(@"%@",pClass);
    }
    return 0;
}

這時(shí)我們通過(guò)lldb進(jìn)行調(diào)試:

lldb-cache_t

可以看出方法執(zhí)行前后忍啤,_buckets_mask仙辟、_occupied都發(fā)生了變化同波,我們發(fā)現(xiàn)有一個(gè)struct bucket_t *buckets()可以打印buckets
buckets

但是_sel_imp并不是我們要的,我們通過(guò)sel()imp(Class)打印看看:
sel

imp

發(fā)現(xiàn)這時(shí)打印出來(lái)的就是我們剛剛執(zhí)行的方法sayHello叠国,說(shuō)明在沒(méi)有調(diào)用方法前未檩,cache是沒(méi)有緩存的,在調(diào)用一次后cache中就有了一個(gè)緩存粟焊,即調(diào)用一次方法就會(huì)緩存一次方法

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末冤狡,一起剝皮案震驚了整個(gè)濱河市孙蒙,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌悲雳,老刑警劉巖挎峦,帶你破解...
    沈念sama閱讀 222,464評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異合瓢,居然都是意外死亡坦胶,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門晴楔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)顿苇,“玉大人,你說(shuō)我怎么就攤上這事税弃〖退辏” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 169,078評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵则果,是天一觀的道長(zhǎng)蜂科。 經(jīng)常有香客問(wèn)我,道長(zhǎng)短条,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 59,979評(píng)論 1 299
  • 正文 為了忘掉前任才菠,我火速辦了婚禮茸时,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘赋访。我一直安慰自己可都,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,001評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布蚓耽。 她就那樣靜靜地躺著渠牲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪步悠。 梳的紋絲不亂的頭發(fā)上签杈,一...
    開(kāi)封第一講書人閱讀 52,584評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音鼎兽,去河邊找鬼答姥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛谚咬,可吹牛的內(nèi)容都是我干的鹦付。 我是一名探鬼主播,決...
    沈念sama閱讀 41,085評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼择卦,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼敲长!你這毒婦竟也來(lái)了郎嫁?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 40,023評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤祈噪,失蹤者是張志新(化名)和其女友劉穎泽铛,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體钳降,經(jīng)...
    沈念sama閱讀 46,555評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡厚宰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,626評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了遂填。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铲觉。...
    茶點(diǎn)故事閱讀 40,769評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖吓坚,靈堂內(nèi)的尸體忽然破棺而出撵幽,到底是詐尸還是另有隱情,我是刑警寧澤礁击,帶...
    沈念sama閱讀 36,439評(píng)論 5 351
  • 正文 年R本政府宣布盐杂,位于F島的核電站,受9級(jí)特大地震影響哆窿,放射性物質(zhì)發(fā)生泄漏链烈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,115評(píng)論 3 335
  • 文/蒙蒙 一挚躯、第九天 我趴在偏房一處隱蔽的房頂上張望强衡。 院中可真熱鬧,春花似錦码荔、人聲如沸漩勤。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,601評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)越败。三九已至,卻和暖如春硼瓣,著一層夾襖步出監(jiān)牢的瞬間究飞,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,702評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工堂鲤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留噪猾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,191評(píng)論 3 378
  • 正文 我出身青樓筑累,卻偏偏與公主長(zhǎng)得像袱蜡,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子慢宗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,781評(píng)論 2 361