一、缓存Cache在哪?
缓存Cache存在类里面,从类占比第16个字节开始。
0x100c071d0就是Cache_t的内存地址。
取到cache_t地址
打印出来看,里面参数也不明白是什么意思,这时候我们就需要去看cache_t的数据结构。
![]()
cache_t数据结构如下,这样就跟上面的值对应起来了,但是每个字段是什么意思呢?
先看一下这个数据结构在内存中占用多少内存? _bucketsAndMaybeMask 是一个 unsigned long类型的,占用8个字节。另一个是联合体,按占用最大空间的元素取,_originalPreoptCache占8个字节,所以这个联合体在内存中也占用8个字节。所以整个数据结构占用16个字节。
typedef unsigned long uintptr_t;再接着往下看,cache_t的方法,insert方法,在这个方法内就是具体的缓存实现,sel,imp,receiver.![]()
IMP和sel就是存在bucket_t内,看下面数据结构
backet_t数据读取和存储
![]()
void cache_t::insert(SEL sel, IMP imp, id receiver)
{
mask_t newOccupied = occupied() + 1;
unsigned oldCapacity = capacity(), capacity = oldCapacity;
if (slowpath(isConstantEmptyCache())) {
// Cache is read-only. Replace it.
if (!capacity) capacity = INIT_CACHE_SIZE;
reallocate(oldCapacity, capacity, /* freeOld */false);
}
else if (fastpath(newOccupied + CACHE_END_MARKER <= cache_fill_ratio(capacity))) {
// Cache is less than 3/4 or 7/8 full. Use it as-is.
}
#if CACHE_ALLOW_FULL_UTILIZATION
else if (capacity <= FULL_UTILIZATION_CACHE_SIZE && newOccupied + CACHE_END_MARKER <= capacity) {
// Allow 100% cache utilization for small buckets. Use it as-is.
}
// 当缓存内存超过后,则缓存扩容。
#endif
else {
capacity = capacity ? capacity * 2 : INIT_CACHE_SIZE;
if (capacity > MAX_CACHE_SIZE) {
capacity = MAX_CACHE_SIZE;
}
reallocate(oldCapacity, capacity, true);
}
}
二、缓存的扩容
扩容机制:首先我们得知道你的cpu架构,不同的CPU架构对应的扩容机制是不一样的。 在 arm64 && !LP64 容量的初始值为4,其他架构下为2.
![]()
-
在arm架构下如果缓存大小 <= 总长度的7/8,不扩容
-
在x86架构下缓存大小+1 <= 总长度的3/4,不扩容
-
当总长度小于8的时候, 也不扩容。
-
否则扩容是当前容量的2倍。
三、代码的优秀之处
简单的一句代码,分别说明了在arm架构,在x86架构下的规则说明,这就是源码的牛逼之处