一、cache_t结构解析
1.获取cache,我们通过首地址平移16字节能够拿到cache
打印类对象的内存地址,获取cache内容,发现这些内容我们并不熟悉
我们现在进入源码中查看cache有什么,我们看cache_t里面的方法,因为cache_t是缓存,所以我们找到insert方法(SEL、IMP、receiver)
我们点击进入insert方法里面看到bucket_t,存的是SEL和IMP
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
我们的整个的insert方法就是往这个bucket_t这个数组中插入数据,插入的位置就是通过cache_hash()这个函数经过sel和m获得的
以上我们得出cache的作用是缓存的方法
bucket_t *是个数组,里面不止有一个方法,通过$3加1就可以获取到数组中下一个元素的值
cache里面存放了class和respondsToSelector方法
二、cache的扩容规则
我们通过p调用方法,打印一下看看,我们发现从cache里面只找到了class,没找到respondsToSelector方法,也没有找到method1方法,这里涉及到了扩容
1.我们先来了解一下cache_t
2.cache的扩容
以上我们得出:
在x8664架构下--当缓存的大小等于桶子长度的四分之三的时候进行两倍扩容
在arm64架构下--当缓存的大小大于桶子长度的八分之七的时候进行两倍扩容
当桶子长度大小小于等于8的时候,不会扩容
3.我们在void cache_t::insert(SEL sel, IMP imp, id receiver)方法下打印sel,
所以我们发现从cache里面只找到了class,没找到respondsToSelector方法和method1方法,是在扩容的时候诶释放了,method1方法的调用是在class和respondsToSelector方法之前调用,respondsToSelector方法是在class方法之前调用
static修饰的成员变量不会影响cache的存储
cache占16字节是固定的,存的是内存的首地址