浅析cache_t
一个类的基本参数
struct objc_class : objc_object {
Class ISA;
Class superclass;
cache_t cache;
class_data_bits_t bits; // class_rw_t
}
cache_t cache;看名称我们知道是缓存,它的用途是用来缓存方法的,cache_t本身是缓存bucket
这是它的基本构造,一眼可以看出他是个机构体,
struct cache_t {
struct bucket_t *_buckets; // 重点
mask_t _mask; //重点
mask_t _occupied; //重点
public:
struct bucket_t *buckets();
mask_t mask();
mask_t occupied();
void incrementOccupied();
void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
void initializeToEmpty();
mask_t capacity();
bool isConstantEmptyCache();
bool canBeFreed();
static size_t bytesForCapacity(uint32_t cap);
static struct bucket_t * endMarker(struct bucket_t *b, uint32_t cap);
void expand();
void reallocate(mask_t oldCapacity, mask_t newCapacity);
struct bucket_t * find(cache_key_t key, id receiver);
static void bad_cache(id receiver, SEL sel, Class isa) __attribute__((noreturn));
};
那么里面struct bucket_t *_buckets; mask_t _mask; mask_t _occupied; 这三个到底是干嘛的,我们分别进行探索
_buckets缓存验证
struct bucket_t *_buckets 这个东西我们看下它的内部构造
MethodCacheIMP _imp;
cache_key_t _key
imp 是不是很熟悉,验证cache_t缓存的是方法, 绑定方法的指针和具体实现之间的联系
这里补充一下方法的知识点:
SEL name;
const char *types;
MethodListIMP imp;
这里 SEL 和 imp的关系基本就是书本里面目录 页码和内容的关系,通过SEL 寻找imp,来查找方法的具体实现
我们用实际代码来,我们来验证下cache_t里面确实缓存的是方法
我们定义LGPerson这样一个类
在不调用任何方法前提下打印cache_t 和 buckets
我们通过上图观察断点位置,可以看到在不调用任何方法的情况下 cache_t里面的buckets里面什么都没有
下面我们来调用下sayHello的方法,打印cache_t和buckets做验证
看上图我们了解sayHello这个方法的确是缓存在了cache_t里面,
_mask缓存流程
我们由上图得知_buckets发生改变的同时,_mask也会发生相应的增长.它本身的作用就是开辟当前缓存空间的大小,同时我对mask_t mask() 该函数的一个追踪在大神的指导下,整理了这么缓存一个流程图,补充:mask_t _occupied; 这个是已占用的容量大小
最后补充
这里的方法,系统也并不是说会来一个方法,就会缓存一个,系统也会对其作出相应处理
系统在扩容的时候,原先容器里的数据不是直接拷贝,而是直接清除,下次再进行写入 ,原因有二:1不安全 ,2本身操作速度比较快,下次直接写入更加便捷 .