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

相关文章
相关标签/搜索