iOS 大師養成之路—— cache分析

什麼是cache?

cache 是類結構體中cache_t的結構體指針,至於元類,根元類都是相似,萬物皆對象嘛,在底層就是萬物皆結構體。 具體代碼結構以下:數組

struct bucket_t *_buckets;
    mask_t _mask;
    mask_t _occupied;
複製代碼

_buckets

_buckets 指向緩存塊數據入口的指針,裏面存放的就是bucket_t結構體數據,bucket_t結構體以下:緩存

MethodCacheIMP _imp;//imp,方法指針,存放的是方法的存放地址
    cache_key_t _key;//將方法名轉換成數值型的key
複製代碼

_mask

_mask, 蒙板,salt。 數值=capacity() - 1,總數量-1。做用是用來查找cache時與key進行&運算,同時經過hash函數來獲得一個hash數組下標。查看源碼左右的位置以下:bash

cache_hash(k, m);

static inline mask_t cache_hash(cache_key_t key, mask_t mask) 
{
    return (mask_t)(key & mask);
}

複製代碼

_occupied

_occupied,已佔用的內存塊的數量。用於標記已經佔用的內存塊的大小,用於與capacity()做比較做爲判斷是否須要擴容的條件。下面的流程會講到。less

cache 方法寫入流程

一、調用填充方法

先調用 cache_fill(Class cls, SEL sel, IMP imp, id receiver); 而後 cache_fill_nolock(Class cls, SEL sel, IMP imp, id receiver)函數

a)、類是否已經初始化完成,若是沒有初始化直接 return if (!cls->isInitialized()) return;ui

b)、再查找一次緩存,以防在加鎖成功前有別的線程緩存成功了方法,若是找到直接返回 if (cache_getImp(cls, sel)) return;spa

c)、準備條件,獲取當前類的cache,將方法名轉化成數值類型的key,記錄將要佔用的容量+1,獲取當前的總容量capacity() cache_t *cache = getCache(cls); cache_key_t key = getKey(sel); mask_t newOccupied = cache->occupied() + 1; mask_t capacity = cache->capacity();線程

d)、判斷cache是不是隻讀的,若是是隻讀的從新開闢指針

if (cache->isConstantEmptyCache()) {
        // Cache is read-only. Replace it.
        cache->reallocate(capacity, capacity ?: INIT_CACHE_SIZE);
    }
複製代碼

e)、判斷是否佔有的容量是否超過總容量的3/4,若是超過擴容 cache->expand(); 容量翻倍,抹掉以前緩存的數據,從新賦值capacity(),maskcode

else if (newOccupied <= capacity / 4 * 3) {
        // Cache is less than 3/4 full. Use it as-is.
    }
    else {
        // Cache is too full. Expand it.
        cache->expand();
    }
複製代碼

f)、根據key查找對應的bucket,若是找到或者key() == 0也就是說尚未開始緩存方法,一樣返回對應的bucket。若是查找了全部的bucket都沒找到,說明這是一個壞的內存調用bad_cache(receiver, (SEL)k, cls);報錯誤信息。

bucket_t *bucket = cache->find(key, receiver);
複製代碼

七、若是key() == 0 說明是新開闢的bucket,_occupied++;

if (bucket->key() == 0) cache->incrementOccupied();
複製代碼

八、賦值bucket->set(key, imp);

bucket->set(key, imp);
複製代碼

到此,cache的寫入和查找流程均清晰明朗。

有興趣一塊兒研究底層的朋友能夠加QQ交流

QQ:578200388

郵箱:578200388@qq.com

相關文章
相關標籤/搜索