前言
oc 对象的本质与isa 和 isa 类的底层原理结构 分别分析了isa和bits。类里面的成员变量还有superclass和cache,今天就来探究下cache的底层原理。
准备工作
cache 结构分析
cache_t
结构图
首先探究cache
的类型cache_t
,源码中查看cache_t
具体类型是结构体
struct cache_t {
private:
explicit_atomic<uintptr_t> _bucketsAndMaybeMask;
union {
struct {
explicit_atomic<mask_t> _maybeMask;
#if __LP64__
uint16_t _flags;
#endif
uint16_t _occupied;
};
explicit_atomic<preopt_cache_t *> _originalPreoptCache;
};
/*
#if defined(__arm64__) && __LP64__
#if TARGET_OS_OSX || TARGET_OS_SIMULATOR
// __arm64__的模拟器
#define CACHE_MASK_STORAGE CACHE_MASK_STORAGE_HIGH_16_BIG_ADDRS
#else
//__arm64__的真机
#define CACHE_MASK_STORAGE CACHE_MASK_STORAGE_HIGH_16
#endif
#elif defined(__arm64__) && !__LP64__
//32位 真机
#define CACHE_MASK_STORAGE CACHE_MASK_STORAGE_LOW_4
#else
//macOS 模拟器
#define CACHE_MASK_STORAGE CACHE_MASK_STORAGE_OUTLINED
#endif
****** 中间是不同的架构之间的判断 主要是用来不同类型 mask 和 buckets 的掩码
*/
public:
void incrementOccupied();
void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
void reallocate(mask_t oldCapacity, mask_t newCapacity, bool freeOld);
unsigned capacity() const;
struct bucket_t *buckets() const;
Class cls() const;
void insert(SEL sel, IMP imp, id receiver);
// 下面是基本上都是其他的方法的方法
};
复制代码
_bucketsAndMaybeMask
变量uintptr_t
占8字节和isa_t中的bits类似,也是一个指针类型里面存放地址- 联合体里有一个结构体和一个结构体指针
_originalPreoptCache
- 结构体中有三个成员变量
_maybeMask
,_flags
,_occupied
。__LP64__指的是Unix和Unix类系统(Linx和macOS) _originalPreoptCache
和结构体是互斥的,_originalPreoptCache
初始时候的缓存,现在探究类中的缓存,这个变量基本不会用到cache_t
提供了公用的方法去获取值,以及根据不同的架构系统去获取mask和buckets
探究
- 当需要缓存的方法所占的容量总容量3/4是就会直接走缓存流程
- 探究一些底层源码就会发现,苹果的设计思想,做什么事情都会留有余地。一方面可能为了日后的优化或者扩展,另一方面可能是为了安全,内存对齐也是这样
- 容量超过3/4,系统此时会进行两倍扩容,扩容的最大容量不会超过mask的最大值2^15
- 扩容的时候会进行一步重要的操作,开辟新的内存,释放回收旧的内存,此时的freeOld = true
缓存方法
- 首先拿到bucket()指向开辟这块内存首地址,也就是第一个bucket的地址,bucket()既不是数组也不是链表,只是一块连续的内存
- hash函数根据缓存sel和mask,计算出hash下标。为什么需要mask呢?mask的实际作用是告诉系统你只能存前capacity – 1中的位置,比如capacity = 4时,缓存的方法只能存前面3个空位
- 开始缓存,当前的位置没有数据,就缓存该方法。如果该位置有方法且和你的方法一样,说明该方法缓存过了,直接return。如果存在hash冲突,下标一样,sel不一样,此时会再次hash,冲突解决继续缓存
insert调用流程
- 调用
insert
方法流程:[instance method]
底层实现objc_msgSend --> _objc_msgSend_uncached --> lookUpImpOrForward --> log_and_fill_cache --> cache_t::insert
总结
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END