缓存Cache_t
struct cache_t { // 16
struct bucket_t *_buckets; // 8
mask_t _mask; // 4
mask_t _occupied; // 4
...
bucket_t
struct bucket_t {
#if __arm64__
MethodCacheIMP _imp;
cache_key_t _key;
#else
cache_key_t _key;
MethodCacheIMP _imp;
#endif
...
}
cache_t 缓存的是 方法 method_t
:
struct method_t {
SEL name;
const char *type;
MethodListIMP imp;
}
缓存流程
缓存的入口是:cache_fill_nolock
函数

1、首先我们从缓存的入口开始分析,一进入到cache_fill_nolock
函数,先查找现有的缓存中是否有对应的方法,有就返回,没有就继续往下走,其中通过sel创建一个key cache_key_t key = getKey(sel);
2、判断现有的缓存是不是空缓存,
如果条件为true
,就去创建一个新的buckets桶子,把_mask = newMask; _occupied = 0;
,如下:
cache->reallocate(capacity,capacity ? : INIT_CACHE_SIZE);
通过cache->find(key, receiver)
找到刚创建的 buckets,再将新的方法存放进去bucket->set(key, imp);
在cache->find(key, receiver)函数中,是怎么找到缓存bucket_t的呢?
首先通过cache_hash
函数计算出key值对应的index值 begin,然后根据这些索引找到bucket_t,如果遍历完后都没有找到的话,说明查找失败,那就会调用bad_cache方法,如下图:

如果缓存里的存储大小 小于
开辟占用的3/4,不作任何处理仅需往下走;
如果缓存里的存储大小 大于
开辟占用的3/4,就需要进行扩容了。
//开始扩容
cache->expend();

扩容是按照原来的2倍来进行的,扩容后,又和之前一样重新创建一个新的buckets。
接着继续查找这个刚创建的buckets,将方法放进buckets中去。
在重新创建一个新的buckets时,会将原来的方法缓存清空掉。如果不清空内存的话,以后如果方法缓存的多了,对应的查找速度也会有一定的影响,内存平移也是一个麻烦。

网友评论