cache_t分析

2020-09-18  本文已影响0人  北京_小海

一、初探cache_t

1.cache_t结构

首先找到objc_class

点击cache进去看看

太多了 就不都截图了 看看宏定义是什么回事

CACHE_MASK_STORAGE_HIGH_16 : 真机&&64位

CACHE_MASK_STORAGE_LOW_4 : 真机&&非64位

CACHE_MASK_STORAGE_OUTLINED:模拟器和Mac呗

bucket_t结构

cache_t中的_buckets、_mask、_occupied从字面意思上理解为桶、面具、占据,但是我们不知道这三个的作用是否与他们的名字有关系,下面我们先从LLDB打印一些信息来看看

2.lldb调试

代码准备

2.1开始调试

调用sayhello

我们可以看到想要的东西了(_buckets, _mask, _flags, _occupied)

内部有很多方法

通过调用buckets()查看结构

发现包含sel和imp 看一下源码方法

调用获取

2.2多个方法调试

发现 _occupied有变化,这个我们一会在分析,我们现在先了解 buckets

找不到saycode

那我大胆猜一下!buckets有s,那他是不是有多个?,会不会是个类似数组结构?那我通过指针偏移可不可以得到想要的东西?那验证一下呗!

搞定 现在我们了解了buckets里面存sel和imp了

二. cache_t实现原理分析

_occupied如何变化的?而且当方法增多,mask也改变。还有buckets怎么存的?

看到了incrementOccupied,让我们看看谁调用的

找到了insert  全局搜索 找到cache_fill

全局搜索cache_fill,发现在写入之前,还有一步操作,即cache读取,即查找sel-imp,

本文的重点还是分析cache存储的原理,接下来根据cache_t写入的流程图,着重分析insert方法insert方法分析

大致分为三步

第一步:计算出当前的缓存占用量 

根据occupied的值计算出当前的缓存占用量,当属性未赋值及无方法调用时,此时的occupied()为0,而newOccupied为1,如上图所示

alloc申请空间时,此时的对象已经创建,如果再调用init方法,occupied也会+1

当有属性赋值时,会隐式调用set方法,occupied也会增加,即有几个属性赋值,occupied就会在原有的基础上加几个

当有方法调用时,occupied也会增加,即有几次调用,occupied就会在原有的基础上加几个

第二步:根据缓存占用量判断执行的操作

reallocate方法:开辟空间

该方法,在第一次创建以及两倍扩容时,都会使用,其源码实现如图所示

allocateBuckets方法:向系统申请开辟内存,即开辟bucket,此时的bucket只是一个临时变量

setBucketsAndMask方法:将临时的bucket存入缓存中,此时的存储分为两种情况:

如果是真机,根据bucket和mask的位置存储,并将occupied占用设置为0

如果不是真机,正常存储bucket和mask,并将occupied占用设置为0

如果有旧的buckets,需要清理之前的缓存,即调用cache_collect_free方法,其源码实现如下

该方法的实现主要有以下几步:

_garbage_make_room方法:创建垃圾回收空间

如果是第一次,需要分配回收空间

如果不是第一次,则将内存段加大,即原有内存*2

记录存储这次的bucket

cache_collect方法:垃圾回收,清理旧的bucket

第三步:针对需要存储的bucket进行内部imp和sel赋值

这部分主要是根据cache_hash方法,即哈希算法 ,计算sel-imp存储的哈希下标,分为以下三种情况: 如果哈希下标的位置未存储sel,即该下标位置获取sel等于0,此时将sel-imp存储进去,并将occupied占用大小加1 如果当前哈希下标存储的sel 等于 即将插入的sel,则直接返回 如果当前哈希下标存储的sel 不等于 即将插入的sel,则重新经过cache_next方法 即哈希冲突算法,重新进行哈希计算,得到新的下标,再去对比进行存储

cache_hash:哈希算法

cache_next:哈希冲突算法

最后将上述流程总结一个流程图

画图软件用得少 图不太好看 谅解哈~~

上一篇下一篇

猜你喜欢

热点阅读