在OC底层探索09-cache_t实现原理探索中已经对cache缓存的机制做了介绍,但是这文章是基于objc4-781来探索的。技术更新的太快了,在objc4-818中cache_t的结构又发生了很大的变化。与此同时缓存的过程中也有一些小的优化。
objc4-781中的cache_t结构
objc4-818中的cache_t结构
- 通过一个
指针
和 一个联合体
来完成数据的存储。通过观察也只是对结构进行了一些优化,其他思路还是不变的。 - 通过结构的变化,来兼容不同架构下的数据存储结构。相信一定是为了适应越来越多的架构。
使用lldb来调试cache
前提不变:使用lldb调试的前提是你需要有lib-objc的源码环境
- 发现通过
buckets()
函数来进行lldb调试,和老版本并没有区别,有兴趣的可以通过最上方的链接去之前的文中看看。
1. 脱离源码来调试cache(模拟器)
前提: 模拟器环境
本文的重头戏,脱离源码来进行调试和测试。
代码语言:javascript复制//模拟器
typedef uint32_t mask_t;
struct HR_bucket_t {
SEL sel;
IMP imp;
};
struct HR_cache_t {
uintptr_t _bucketsAndMaybeMask;
union {
struct {
mask_t _maybeMask;
uint16_t _flags;
uint16_t _occupied;
};
};
//该方法是模仿源码
static constexpr uintptr_t bucketsMask = ~0ul;
struct HR_bucket_t* buckets() const
{
return (HR_bucket_t *)(_bucketsAndMaybeMask & bucketsMask);
}
};
struct HR_class_data_bits_t {
uintptr_t bits;
};
struct HR_objc_class {
Class ISA;
Class superclass;
struct HR_cache_t cache; // formerly cache pointer and vtable
struct HR_class_data_bits_t bits;
};
调用
代码语言:javascript复制int main() {
HRTest * t = [HRTest alloc];
struct HR_objc_class *obj = (__bridge struct HR_objc_class *)(HRTest.class);
NSLog(@"mask:%u---occupied:%u",obj->cache._maybeMask,obj->cache._occupied);
for (mask_t i = 0; i < obj->cache._maybeMask; i ) {
struct HR_bucket_t bucket = obj->cache.buckets()[i];
NSLog(@"sel:%@---imp:%p",NSStringFromSelector(bucket.sel),bucket.imp);
}
}
查看结果
- 在模拟下的结果和旧版本是一致的。
2. 缓存过程中的一些优化
- 定义
FULL_UTILIZATION_CACHE_SIZE= 1 << 3
=8
为小缓存区
。应该是考虑到小缓存区时hash冲突不会造成太大性能损耗。 - 多了这部分逻辑,相比于旧逻辑
容量可以在4或者8的情况下全部放满。
只有真机的情况下才生效