类的底层探索 — cache详解

256 阅读2分钟

一、cache_t结构解析

1.获取cache,我们通过首地址平移16字节能够拿到cache 图片.png 打印类对象的内存地址,获取cache内容,发现这些内容我们并不熟悉 WechatIMG371.png 我们现在进入源码中查看cache有什么,我们看cache_t里面的方法,因为cache_t是缓存,所以我们找到insert方法(SEL、IMP、receiver) WechatIMG373.png 我们点击进入insert方法里面看到bucket_t,存的是SEL和IMP WechatIMG374.png bucket_t是一个哈希表(散列表,可能存在哈希冲突)

capacity:通过源码我们发现capacity等于oldCapacity,oldCapacity是通过capacity()获得的,capacity()函数中又调用了mask()函数,mask()函数就是读取_maybeMask的值,_maybeMask就是bucket_t的长度 - 1,capacity的值就是bucket_t的长度

m :capacity - 1,就代表bucket_t长度 - 1 begin是根据哈希函数得到的

sel和imp插入到什么地方,是通过哈希函数获取的,sel转换数字,这个数字是个比较大的数字,比较大的数字 & 比较小的数字得到的也是个比较小的(一定不会超过较小的,最大值就是等于比较小的值),也就是说这个哈希函数中最大的值就是m,就是bucket_t长度 - 1 图片.png

我们的整个的insert方法就是往这个bucket_t这个数组中插入数据,插入的位置就是通过cache_hash()这个函数经过sel和m获得的

以上我们得出cache的作用是缓存的方法

WechatIMG380.png bucket_t *是个数组,里面不止有一个方法,通过$3加1就可以获取到数组中下一个元素的值 WechatIMG381.png cache里面存放了class和respondsToSelector方法

二、cache的扩容规则

我们通过p调用方法,打印一下看看,我们发现从cache里面只找到了class,没找到respondsToSelector方法,也没有找到method1方法,这里涉及到了扩容 图片.png 1.我们先来了解一下cache_t 图片.png 2.cache的扩容 图片.png 以上我们得出:

在x8664架构下--当缓存的大小等于桶子长度的四分之三的时候进行两倍扩容

在arm64架构下--当缓存的大小大于桶子长度的八分之七的时候进行两倍扩容

当桶子长度大小小于等于8的时候,不会扩容

3.我们在void cache_t::insert(SEL sel, IMP imp, id receiver)方法下打印sel, 图片.png 所以我们发现从cache里面只找到了class,没找到respondsToSelector方法和method1方法,是在扩容的时候诶释放了,method1方法的调用是在class和respondsToSelector方法之前调用,respondsToSelector方法是在class方法之前调用

static修饰的成员变量不会影响cache的存储

cache占16字节是固定的,存的是内存的首地址