前语

咱们知道objc_class有4个特点,第一个是从objc_object承继过来的ISA,是个objc_class *结构体指针,占8字节,superclass同样是8字节的objc_class *指针,接下去是cachebits,本文就cache的结构和作用开端研讨。

类的底层探究-cache

cache的结构剖析

cache的巨细

特点cache的类型是cache_t类型,检查cache_t源码,除去办法和静态变量,影响cache的巨细的有如下

类的底层探究-cache
cache_t是个结构体,有两个特点:

  • 第一个是一个8字节的指针_bucketsAndMaybeMask
  • 第二个是一个互斥的联合体

联合体的巨细: 8字节的指针_originalPreoptCache和一个结构体互斥,由联合体的特性也能推算结构体的巨细也是8字节,所以联合体的巨细是8字节,从而推出cache_t的巨细是16个字节

联合体内包括的结构体依据不同的架构有不同的状况,咱们选一种如图中标颜色的架构剖析

  • typedef uint32_t mask_t; mask_t4个字节
  • _occupied是uint16_t,2个字节
  • _flags是uint16_t,2个字节
  • 所以加起来也是8个字节,验证了上述猜测

小结:cache的巨细是16个字节

cache的特点详细剖析

_bucketsAndMaybeMask

望文生义_bucketsAndMaybeMask这个特点包括了buckets,或许也包括mask,那么一个8字节的指针是怎么存下bucketsmask的呢?带着这个疑问咱们检查cache_t里边的办法,找到了setBucketsAndMask,大局查找,咱们发现这个办法有三个完成

类的底层探究-cache

类的底层探究-cache

类的底层探究-cache
这三个办法详细走哪个是依据架构区分的,检查架构的宏界说:

类的底层探究-cache

结合架构剖析setBucketsAndMask办法能够知道:

  • CACHE_MASK_STORAGE_OUTLINED的架构_bucketsAndMaybeMask存的便是bucketsmask是存在_mask特点里边
  • CACHE_MASK_STORAGE_HIGH_16或许CACHE_MASK_STORAGE的架构下maskShift=48,所以_bucketsAndMaybeMask的高16位存mask,低48位存buckets
  • CACHE_MASK_STORAGE_LOW_4的架构下高48位存buckets,低16位存的是objc::mask16ShiftBits(mask)
    类的底层探究-cache
    mask16ShiftBits办法是获取0xffff需求右移多少位能够得到mask 至此咱们总算明白_bucketsAndMaybeMask其间maybe的意思了,依据不同的架构会存buckets,可是mask存在与否或许就maybe了。

_originalPreoptCache

大局查找能够看到这些地方有用到这个特点

类的底层探究-cache

类的底层探究-cache

类的底层探究-cache

类的底层探究-cache
看代码注释这个变量大概是跟同享缓存或许是缓存的测验有关,在libobjc没看到其他地方的引用,看来一般状况是不会用到这个变量的,所以咱们暂时先不重点研讨这个变量了

_mask

类的底层探究-cache
capacity望文生义便是cache的容量,mask便是cache的容量-1,当然mask的获取是依据mask()办法,也是依据架构不同要么直接拿_mask的特点要么从_bucketsAndMaybeMask这儿边取,和存值是个反操作,这儿不再赘述

类的底层探究-cache

类的底层探究-cache

类的底层探究-cache

_occupied

类的底层探究-cache

这个就一个地方完成,所有架构都相同,是cache里边已经缓存的办法的个数。

cache的lldb调试

类的底层探究-cache
断点持续跑到study4

类的底层探究-cache
这时分问题来了,咱们分明跑了init,study1,study2,study3 4个办法了,为什么_occupied是2? 咱们先打印下详细存了哪两个办法

类的底层探究-cache
这儿咱们打印buckets的第0个方位的内容发现selimp都是空的,这是为什么呢? 经过内存平移咱们持续打印buckets

类的底层探究-cache

咱们发现的确存在study2study3这两个办法,所以_occupied是2没问题,那么init,study1这两个办法去哪去了,一起咱们发现study2study3的办法并不是次序存的,那么buckets一定不是咱们了解的数组这样的接连存储的结构,或许有点像哈希数组的感觉。为了验证咱们的猜测咱们去找cache_t关于办法的刺进的函数,咱们猜测是add或许是insert这样的办法,果然是这样的

类的底层探究-cache

cache的insert办法剖析

void cache_t::insert(SEL sel, IMP imp, id receiver)
{
    lockdebug::assert_locked(&runtimeLock);
    // Never cache before +initialize is done
    if (slowpath(!cls()->isInitialized())) {
        return;
    }
    if (isConstantOptimizedCache()) {
        _objc_fatal("cache_t::insert() called with a preoptimized cache for %s",
                    cls()->nameForLogging());
    }
#if DEBUG_TASK_THREADS
    return _collecting_in_critical();
#else
#if CONFIG_USE_CACHE_LOCK
    mutex_locker_t lock(cacheUpdateLock);
#endif
    ASSERT(sel != 0 && cls()->isInitialized());
    // Use the cache as-is if until we exceed our expected fill ratio.
    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);
    }
    bucket_t *b = buckets();
    mask_t m = capacity - 1;
    mask_t begin = cache_hash(sel, m);
    mask_t i = begin;
    // Scan for the first unused slot and insert there.
    // There is guaranteed to be an empty slot.
    do {
        if (fastpath(b[i].sel() == 0)) {
            incrementOccupied();
            b[i].set<Atomic, Encoded>(b, sel, imp, cls());
            return;
        }
        if (b[i].sel() == sel) {
            // The entry was added to the cache by some other thread
            // before we grabbed the cacheUpdateLock.
            return;
        }
    } while (fastpath((i = cache_next(i, m)) != begin));
    bad_cache(receiver, (SEL)sel);
#endif // !DEBUG_TASK_THREADS
}

类的底层探究-cache
新的办法缓存个数是本来的+1这是当然,毕竟新刺进一个办法

类的底层探究-cache
第一次没缓存过办法会来这儿边,依据架构不同初始化不同的容量,我这边的架构是mac os 模仿器 capacity=4

类的底层探究-cache
然后会分配buckets,依据freeOld来收回内存,当然第一次不需求收回

类的底层探究-cache
CACHE_END_MARKER=1

类的底层探究-cache
这段代码的含义是缓存的办法数+1假如超过了3/4的话需求扩容,当然不同的架构也或许是7/扩容 扩容是2倍扩容

类的底层探究-cache
这段代码是要害 咱们关注下cache_hash这个办法,第一个参数是sel,第二个是capacity-1也便是mask

类的底层探究-cache
看到这儿咱们经过哈希函数得到初始下标begin,前面关于buckets的数据结构这儿也得到了验证,其实便是哈希数组。

类的底层探究-cache
经过cache_next进行遍历

  • 假如没有存过就存办法,并且incrementOccupied
  • 假如办法存在就直接返回
  • 循环结束时又到了开端的办法

cache的模仿代码

不需求在libobjc的源码环境,新建一个工程咱们复原cache_t的结构

模仿器下复原cache_t结构

struct sp_class_data_bits_t {
  uintptr_t bits;
};
struct sp_bucket_t {
  //真机环境是先_imp后_sel
  SEL _sel;
  IMP _imp;
};
struct sp_cache_t {
  struct sp_bucket_t* _buckets; // 模仿器这个_bucketsAndMaybeMask其实便是_buckets,真机环境复杂点,留个读者探求
  uint32_t  _mask;
  uint16_t  _occupied;
  uint16_t  _flags;
};
struct sp_objc_class {
  Class isa; // 留意这儿的isa是承继父类的
  Class superclass;
  struct sp_cache_t cache;
  struct sp_class_data_bits_t bits;
};

复原cache_t的结构后咱们能够经过桥接__bridgeSPObject类桥接成sp_objc_class咱们自己界说的结构体,这样咱们能够剖析每次调用办法时分_mask_occupied,已经缓存的办法列表的改变

void test() {
  struct sp_objc_class*sp_class = (__bridge struct sp_objc_class *)(SPObject.class);
  NSLog(@"%u-%u- %u", sp_class->cache._mask, 
  sp_class->cache._occupied,  
  sp_class->cache._flags);
  for(int i = 0; i < sp_class->cache._mask; i ++) {
    struct sp_bucket_t bucket = sp_class->cache._buckets[i];
    NSLog(@"%@-%p-%d", NSStringFromSelector(bucket._sel), bucket._imp, i);
  }
  NSLog(@"***************");
}
int main(int argc, const char * argv[]) {
    @autoreleasepool {
      SPObject *p = [[SPObject alloc] init];
      test();
      [p study1];
      test();
      [p study2];
      test();
      [p study3];
      test();
      [p study4];
      test();
      [p study5];
      test();
      [p study6];
      test();
      [p study7];
      test();
    }
    return 0;
}

控制台输出如下:

**2023-01-10 22:53:01.719984+0800 KCObjcBuild[69345:16969273] 3-1- 32784**
**2023-01-10 22:53:01.723247+0800 KCObjcBuild[69345:16969273] init-0x8d5b748-0**
**2023-01-10 22:53:01.723601+0800 KCObjcBuild[69345:16969273] (null)-0x0-1**
**2023-01-10 22:53:01.723677+0800 KCObjcBuild[69345:16969273] (null)-0x0-2**
**2023-01-10 22:53:01.723737+0800 KCObjcBuild[69345:16969273] *****************
**2023-01-10 22:53:01.723870+0800 KCObjcBuild[69345:16969273] 3-2- 32784**
**2023-01-10 22:53:01.723993+0800 KCObjcBuild[69345:16969273] init-0x8d5b748-0**
**2023-01-10 22:53:01.724064+0800 KCObjcBuild[69345:16969273] study1-0xbf08-1**
**2023-01-10 22:53:01.724122+0800 KCObjcBuild[69345:16969273] (null)-0x0-2**
**2023-01-10 22:53:01.724177+0800 KCObjcBuild[69345:16969273] *****************
**2023-01-10 22:53:01.724250+0800 KCObjcBuild[69345:16969273] 7-1- 32784**
**2023-01-10 22:53:01.724320+0800 KCObjcBuild[69345:16969273] study2-0xbf18-0**
**2023-01-10 22:53:01.724379+0800 KCObjcBuild[69345:16969273] (null)-0x0-1**
**2023-01-10 22:53:01.724433+0800 KCObjcBuild[69345:16969273] (null)-0x0-2**
**2023-01-10 22:53:01.724494+0800 KCObjcBuild[69345:16969273] (null)-0x0-3**
**2023-01-10 22:53:01.724546+0800 KCObjcBuild[69345:16969273] (null)-0x0-4**
**2023-01-10 22:53:01.737091+0800 KCObjcBuild[69345:16969273] (null)-0x0-5**
**2023-01-10 22:53:01.737155+0800 KCObjcBuild[69345:16969273] (null)-0x0-6**
**2023-01-10 22:53:01.737200+0800 KCObjcBuild[69345:16969273] *****************
**2023-01-10 22:53:01.737297+0800 KCObjcBuild[69345:16969273] 7-2- 32784**
**2023-01-10 22:53:01.737367+0800 KCObjcBuild[69345:16969273] study2-0xbf18-0**
**2023-01-10 22:53:01.737422+0800 KCObjcBuild[69345:16969273] study3-0xbf68-1**
**2023-01-10 22:53:01.737468+0800 KCObjcBuild[69345:16969273] (null)-0x0-2**
**2023-01-10 22:53:01.737512+0800 KCObjcBuild[69345:16969273] (null)-0x0-3**
**2023-01-10 22:53:01.737556+0800 KCObjcBuild[69345:16969273] (null)-0x0-4**
**2023-01-10 22:53:01.737597+0800 KCObjcBuild[69345:16969273] (null)-0x0-5**
**2023-01-10 22:53:01.737638+0800 KCObjcBuild[69345:16969273] (null)-0x0-6**
**2023-01-10 22:53:01.737681+0800 KCObjcBuild[69345:16969273] *****************
**2023-01-10 22:53:01.737742+0800 KCObjcBuild[69345:16969273] 7-3- 32784**
**2023-01-10 22:53:01.737791+0800 KCObjcBuild[69345:16969273] study2-0xbf18-0**
**2023-01-10 22:53:01.749535+0800 KCObjcBuild[69345:16969273] study3-0xbf68-1**
**2023-01-10 22:53:01.749639+0800 KCObjcBuild[69345:16969273] (null)-0x0-2**
**2023-01-10 22:53:01.749687+0800 KCObjcBuild[69345:16969273] (null)-0x0-3**
**2023-01-10 22:53:01.749731+0800 KCObjcBuild[69345:16969273] (null)-0x0-4**
**2023-01-10 22:53:01.749776+0800 KCObjcBuild[69345:16969273] (null)-0x0-5**
**2023-01-10 22:53:01.749819+0800 KCObjcBuild[69345:16969273] study4-0xbf78-6**
**2023-01-10 22:53:01.749858+0800 KCObjcBuild[69345:16969273] *****************
**2023-01-10 22:53:01.749931+0800 KCObjcBuild[69345:16969273] 7-4- 32784**
**2023-01-10 22:53:01.749978+0800 KCObjcBuild[69345:16969273] study2-0xbf18-0**
**2023-01-10 22:53:01.750022+0800 KCObjcBuild[69345:16969273] study3-0xbf68-1**
**2023-01-10 22:53:01.750061+0800 KCObjcBuild[69345:16969273] (null)-0x0-2**
**2023-01-10 22:53:01.750099+0800 KCObjcBuild[69345:16969273] (null)-0x0-3**
**2023-01-10 22:53:01.750137+0800 KCObjcBuild[69345:16969273] (null)-0x0-4**
**2023-01-10 22:53:01.750180+0800 KCObjcBuild[69345:16969273] study5-0xbf48-5**
**2023-01-10 22:53:01.750222+0800 KCObjcBuild[69345:16969273] study4-0xbf78-6**
**2023-01-10 22:53:01.750259+0800 KCObjcBuild[69345:16969273] *****************
**2023-01-10 22:53:01.750315+0800 KCObjcBuild[69345:16969273] 7-5- 32784**
**2023-01-10 22:53:01.750360+0800 KCObjcBuild[69345:16969273] study2-0xbf18-0**
**2023-01-10 22:53:01.750449+0800 KCObjcBuild[69345:16969273] study3-0xbf68-1**
**2023-01-10 22:53:01.750522+0800 KCObjcBuild[69345:16969273] (null)-0x0-2**
**2023-01-10 22:53:01.750566+0800 KCObjcBuild[69345:16969273] (null)-0x0-3**
**2023-01-10 22:53:01.750729+0800 KCObjcBuild[69345:16969273] study6-0xbf58-4**
**2023-01-10 22:53:01.750802+0800 KCObjcBuild[69345:16969273] study5-0xbf48-5**
**2023-01-10 22:53:01.750849+0800 KCObjcBuild[69345:16969273] study4-0xbf78-6**
**2023-01-10 22:53:01.750903+0800 KCObjcBuild[69345:16969273] *****************
**2023-01-10 22:53:01.750981+0800 KCObjcBuild[69345:16969273] 15-1- 32784**
**2023-01-10 22:53:01.751078+0800 KCObjcBuild[69345:16969273] (null)-0x0-0**
**2023-01-10 22:53:01.751140+0800 KCObjcBuild[69345:16969273] (null)-0x0-1**
**2023-01-10 22:53:01.751184+0800 KCObjcBuild[69345:16969273] (null)-0x0-2**
**2023-01-10 22:53:01.751224+0800 KCObjcBuild[69345:16969273] (null)-0x0-3**
**2023-01-10 22:53:01.751264+0800 KCObjcBuild[69345:16969273] (null)-0x0-4**
**2023-01-10 22:53:01.751304+0800 KCObjcBuild[69345:16969273] (null)-0x0-5**
**2023-01-10 22:53:01.751343+0800 KCObjcBuild[69345:16969273] (null)-0x0-6**
**2023-01-10 22:53:01.751381+0800 KCObjcBuild[69345:16969273] (null)-0x0-7**
**2023-01-10 22:53:01.751421+0800 KCObjcBuild[69345:16969273] (null)-0x0-8**
**2023-01-10 22:53:01.751460+0800 KCObjcBuild[69345:16969273] (null)-0x0-9**
**2023-01-10 22:53:01.751500+0800 KCObjcBuild[69345:16969273] (null)-0x0-10**
**2023-01-10 22:53:01.751550+0800 KCObjcBuild[69345:16969273] study7-0xbea8-11**
**2023-01-10 22:53:01.751593+0800 KCObjcBuild[69345:16969273] (null)-0x0-12**
**2023-01-10 22:53:01.751632+0800 KCObjcBuild[69345:16969273] (null)-0x0-13**
**2023-01-10 22:53:01.751670+0800 KCObjcBuild[69345:16969273] (null)-0x0-14**
**2023-01-10 22:53:01.751708+0800 KCObjcBuild[69345:16969273] *****************

咱们看到_mask_occupied的改变是3-1,3-2,7-1,7-2,7-4,7-5,15-1

3-1的解说:第一次办法调用,初始化capacity=4, _mask=capacity-1=3, 并且缓存了一个办法init

3-13-2的解说:调用第二个办法2 + 1 <= 3 / 4 * 4 未达到扩容条件,所以容量不变,_mask也不变还是3,一起新缓存了study1办法,_occupied变为2

3-27-1的解说:调用第三个办法3 + 1 > 3 / 4 * 4满足扩容条件,2倍扩容``capacity = 4 * 2 = 8, _mask=capacity-1=8-1=7,然后重新分配buckets,调用reallocate->setBucketsAndMask,这时_occupied=0,接着在新的buckets(新拓荒的内存空间,所以此刻没有缓存办法)查找study2,未找到,所以刺进办法,一起incrementOccupied,这时这时_occupied=1 所以这便是7-1的来历

7-515-1的解说:调用study7办法 6 + 1 > 3 / 4 * 8满足扩容条件,2倍扩容``capacity = 8 * 2 = 16, _mask=capacity-1=16-1=15,然后重新分配buckets,调用eallocate->setBucketsAndMask,这时_occupied=0,接着在新的buckets(新拓荒的内存空间,所以此刻没有缓存办法)查找study7,未找到,所以刺进办法,一起incrementOccupied,这时这时_occupied=1 所以这便是15-1的来历 咱们看到study7存在的方位是11,也便是经过hash_cache算出来的下标

真机下复原cache_t结构

struct sp_zhenji_bucket_t {
  //真机先imp后sel
  IMP _imp;
  SEL _sel;
};
struct sp_zhenji_cache_t {
  // 真机架构
  unsigned long _bucketsAndMaybeMask;
  uint32_t  _unused;
  uint16_t  _occupied;
  uint16_t  _flags;
  struct sp_zhenji_bucket_t *buckets() {
    //低44位存buckests,中间4位是maskZeroBits
    return (sp_zhenji_bucket_t *)(_bucketsAndMaybeMask << 20 >> 20);
  }
  uint32_t mask() {
    //高16位存mask
    return _bucketsAndMaybeMask >> 48;
  }
};
struct sp_zhenji_objc_class {
  Class isa;
  Class superclass;
  struct sp_zhenji_cache_t cache;
  struct sp_class_data_bits_t bits;
};

改造下模仿器的测验代码咱们能够得到真机的测验代码如下:

void test_zhenji() {
  struct sp_zhenji_objc_class* sp_class = (__bridge struct sp_zhenji_objc_class *)(SPObject.class);
  NSLog(@"%u-%u", sp_class->cache.mask(),
  sp_class->cache._occupied);
  for(int i = 0; i <= sp_class->cache.mask(); i ++) {
    struct sp_zhenji_bucket_t bucket = sp_class->cache.buckets()[i];
    NSLog(@"%@-%p-%d", NSStringFromSelector(bucket._sel), bucket._imp, i);
  }
  NSLog(@"***************");
}
 SPObject *p = [[SPObject alloc] init];
  test_zhenji();
  [p study1];
  test_zhenji();
  [p study2];
  test_zhenji();
  [p study3];
  test_zhenji();
  [p study4];
  test_zhenji();
  [p study5];
  test_zhenji();
  [p study6];
  test_zhenji();
  [p study7];
  test_zhenji();
  [p study1];
  test_zhenji();
  [p study2];
  test_zhenji();
  [p study3];
  test_zhenji();
  [p study4];
  test_zhenji();
  [p study5];
  test_zhenji();
  [p study8];
  test_zhenji();
  [p study9];
  test_zhenji();

运转代码能够得到如下成果:

2023-02-18 15:20:31.981278+0800 TestCache[672:70223] 1-1
2023-02-18 15:20:31.981334+0800 TestCache[672:70223] init-0x240f84019f4523e8-0
2023-02-18 15:20:31.981355+0800 TestCache[672:70223] (null)-0x0-1
2023-02-18 15:20:31.981370+0800 TestCache[672:70223] ***************
2023-02-18 15:20:31.981383+0800 TestCache[672:70223] 1-2
2023-02-18 15:20:31.981403+0800 TestCache[672:70223] init-0x240f84019f4523e8-0
2023-02-18 15:20:31.981423+0800 TestCache[672:70223] study1-0xa02d96010283de70-1
2023-02-18 15:20:31.981438+0800 TestCache[672:70223] ***************
2023-02-18 15:20:31.981451+0800 TestCache[672:70223] 3-1
2023-02-18 15:20:31.981464+0800 TestCache[672:70223] (null)-0x0-0
2023-02-18 15:20:31.981477+0800 TestCache[672:70223] (null)-0x0-1
2023-02-18 15:20:31.981501+0800 TestCache[672:70223] study2-0x4630c2010283de84-2
2023-02-18 15:20:31.981516+0800 TestCache[672:70223] (null)-0x0-3
2023-02-18 15:20:31.981529+0800 TestCache[672:70223] ***************
2023-02-18 15:20:31.981541+0800 TestCache[672:70223] 3-2
2023-02-18 15:20:31.991736+0800 TestCache[672:70223] (null)-0x0-0
2023-02-18 15:20:31.991763+0800 TestCache[672:70223] study3-0x3602cc810283de98-1
2023-02-18 15:20:31.991787+0800 TestCache[672:70223] study2-0x4630c2010283de84-2
2023-02-18 15:20:31.991803+0800 TestCache[672:70223] (null)-0x0-3
2023-02-18 15:20:31.991817+0800 TestCache[672:70223] ***************
2023-02-18 15:20:31.991832+0800 TestCache[672:70223] 3-3
2023-02-18 15:20:31.991853+0800 TestCache[672:70223] study4-0xce7878010283deac-0
2023-02-18 15:20:31.991876+0800 TestCache[672:70223] study3-0x3602cc810283de98-1
2023-02-18 15:20:31.991899+0800 TestCache[672:70223] study2-0x4630c2010283de84-2
2023-02-18 15:20:31.991914+0800 TestCache[672:70223] (null)-0x0-3
2023-02-18 15:20:31.991929+0800 TestCache[672:70223] ***************
2023-02-18 15:20:31.991943+0800 TestCache[672:70223] 3-4
2023-02-18 15:20:31.991962+0800 TestCache[672:70223] study4-0xce7878010283deac-0
2023-02-18 15:20:31.991983+0800 TestCache[672:70223] study3-0x3602cc810283de98-1
2023-02-18 15:20:31.995589+0800 TestCache[672:70223] study2-0x4630c2010283de84-2
2023-02-18 15:20:31.995616+0800 TestCache[672:70223] study5-0x9415be010283dec0-3
2023-02-18 15:20:31.995632+0800 TestCache[672:70223] ***************
2023-02-18 15:20:31.995647+0800 TestCache[672:70223] 7-1
2023-02-18 15:20:31.995660+0800 TestCache[672:70223] (null)-0x0-0
2023-02-18 15:20:31.995673+0800 TestCache[672:70223] (null)-0x0-1
2023-02-18 15:20:31.995693+0800 TestCache[672:70223] study6-0x14913810283ded4-2
2023-02-18 15:20:31.995708+0800 TestCache[672:70223] (null)-0x0-3
2023-02-18 15:20:31.995739+0800 TestCache[672:70223] (null)-0x0-4
2023-02-18 15:20:31.995753+0800 TestCache[672:70223] (null)-0x0-5
2023-02-18 15:20:31.995766+0800 TestCache[672:70223] (null)-0x0-6
2023-02-18 15:20:31.995779+0800 TestCache[672:70223] (null)-0x0-7
2023-02-18 15:20:31.995792+0800 TestCache[672:70223] ***************
2023-02-18 15:20:31.995805+0800 TestCache[672:70223] 7-2
2023-02-18 15:20:31.995818+0800 TestCache[672:70223] (null)-0x0-0
2023-02-18 15:20:31.997287+0800 TestCache[672:70223] (null)-0x0-1
2023-02-18 15:20:31.997311+0800 TestCache[672:70223] study6-0x14913810283ded4-2
2023-02-18 15:20:31.997325+0800 TestCache[672:70223] (null)-0x0-3
2023-02-18 15:20:31.997340+0800 TestCache[672:70223] (null)-0x0-4
2023-02-18 15:20:31.997364+0800 TestCache[672:70223] study7-0xfd311d010283dee8-5
2023-02-18 15:20:31.997378+0800 TestCache[672:70223] (null)-0x0-6
2023-02-18 15:20:31.997391+0800 TestCache[672:70223] (null)-0x0-7
2023-02-18 15:20:31.997403+0800 TestCache[672:70223] ***************
2023-02-18 15:20:31.997416+0800 TestCache[672:70223] 7-3
2023-02-18 15:20:31.997431+0800 TestCache[672:70223] (null)-0x0-0
2023-02-18 15:20:31.997445+0800 TestCache[672:70223] (null)-0x0-1
2023-02-18 15:20:31.997466+0800 TestCache[672:70223] study6-0x14913810283ded4-2
2023-02-18 15:20:31.997481+0800 TestCache[672:70223] (null)-0x0-3
2023-02-18 15:20:31.997501+0800 TestCache[672:70223] study1-0x3a68a5810283de70-4
2023-02-18 15:20:31.997524+0800 TestCache[672:70223] study7-0xfd311d010283dee8-5
2023-02-18 15:20:31.997538+0800 TestCache[672:70223] (null)-0x0-6
2023-02-18 15:20:31.997552+0800 TestCache[672:70223] (null)-0x0-7
2023-02-18 15:20:31.997565+0800 TestCache[672:70223] ***************
2023-02-18 15:20:31.999023+0800 TestCache[672:70223] 7-4
2023-02-18 15:20:31.999040+0800 TestCache[672:70223] (null)-0x0-0
2023-02-18 15:20:31.999053+0800 TestCache[672:70223] (null)-0x0-1
2023-02-18 15:20:31.999074+0800 TestCache[672:70223] study6-0x14913810283ded4-2
2023-02-18 15:20:31.999090+0800 TestCache[672:70223] (null)-0x0-3
2023-02-18 15:20:31.999110+0800 TestCache[672:70223] study1-0x3a68a5810283de70-4
2023-02-18 15:20:31.999133+0800 TestCache[672:70223] study7-0xfd311d010283dee8-5
2023-02-18 15:20:31.999189+0800 TestCache[672:70223] study2-0x7248e6810283de84-6
2023-02-18 15:20:31.999204+0800 TestCache[672:70223] (null)-0x0-7
2023-02-18 15:20:31.999218+0800 TestCache[672:70223] ***************
2023-02-18 15:20:31.999231+0800 TestCache[672:70223] 7-5
2023-02-18 15:20:31.999244+0800 TestCache[672:70223] (null)-0x0-0
2023-02-18 15:20:31.999264+0800 TestCache[672:70223] study3-0x300fee810283de98-1
2023-02-18 15:20:31.999284+0800 TestCache[672:70223] study6-0x14913810283ded4-2
2023-02-18 15:20:31.999298+0800 TestCache[672:70223] (null)-0x0-3
2023-02-18 15:20:31.999320+0800 TestCache[672:70223] study1-0x3a68a5810283de70-4
2023-02-18 15:20:31.999340+0800 TestCache[672:70223] study7-0xfd311d010283dee8-5
2023-02-18 15:20:31.999362+0800 TestCache[672:70223] study2-0x7248e6810283de84-6
2023-02-18 15:20:31.999379+0800 TestCache[672:70223] (null)-0x0-7
2023-02-18 15:20:31.999394+0800 TestCache[672:70223] ***************
2023-02-18 15:20:32.001303+0800 TestCache[672:70223] 7-6
2023-02-18 15:20:32.001327+0800 TestCache[672:70223] study4-0x2e7a3e010283deac-0
2023-02-18 15:20:32.001352+0800 TestCache[672:70223] study3-0x300fee810283de98-1
2023-02-18 15:20:32.001378+0800 TestCache[672:70223] study6-0x14913810283ded4-2
2023-02-18 15:20:32.001394+0800 TestCache[672:70223] (null)-0x0-3
2023-02-18 15:20:32.001414+0800 TestCache[672:70223] study1-0x3a68a5810283de70-4
2023-02-18 15:20:32.001434+0800 TestCache[672:70223] study7-0xfd311d010283dee8-5
2023-02-18 15:20:32.001454+0800 TestCache[672:70223] study2-0x7248e6810283de84-6
2023-02-18 15:20:32.001469+0800 TestCache[672:70223] (null)-0x0-7
2023-02-18 15:20:32.001483+0800 TestCache[672:70223] ***************
2023-02-18 15:20:32.001496+0800 TestCache[672:70223] 7-7
2023-02-18 15:20:32.001517+0800 TestCache[672:70223] study4-0x2e7a3e010283deac-0
2023-02-18 15:20:32.001540+0800 TestCache[672:70223] study3-0x300fee810283de98-1
2023-02-18 15:20:32.001561+0800 TestCache[672:70223] study6-0x14913810283ded4-2
2023-02-18 15:20:32.001580+0800 TestCache[672:70223] study5-0xd00257010283dec0-3
2023-02-18 15:20:32.003027+0800 TestCache[672:70223] study1-0x3a68a5810283de70-4
2023-02-18 15:20:32.003049+0800 TestCache[672:70223] study7-0xfd311d010283dee8-5
2023-02-18 15:20:32.003070+0800 TestCache[672:70223] study2-0x7248e6810283de84-6
2023-02-18 15:20:32.003085+0800 TestCache[672:70223] (null)-0x0-7
2023-02-18 15:20:32.003099+0800 TestCache[672:70223] ***************
2023-02-18 15:20:32.003114+0800 TestCache[672:70223] 7-8
2023-02-18 15:20:32.003136+0800 TestCache[672:70223] study4-0x2e7a3e010283deac-0
2023-02-18 15:20:32.003157+0800 TestCache[672:70223] study3-0x300fee810283de98-1
2023-02-18 15:20:32.003179+0800 TestCache[672:70223] study6-0x14913810283ded4-2
2023-02-18 15:20:32.003200+0800 TestCache[672:70223] study5-0xd00257010283dec0-3
2023-02-18 15:20:32.003221+0800 TestCache[672:70223] study1-0x3a68a5810283de70-4
2023-02-18 15:20:32.003241+0800 TestCache[672:70223] study7-0xfd311d010283dee8-5
2023-02-18 15:20:32.003262+0800 TestCache[672:70223] study2-0x7248e6810283de84-6
2023-02-18 15:20:32.003283+0800 TestCache[672:70223] study8-0x4c7f40810283defc-7
2023-02-18 15:20:32.003298+0800 TestCache[672:70223] ***************
2023-02-18 15:20:32.003317+0800 TestCache[672:70223] 15-1
2023-02-18 15:20:32.003331+0800 TestCache[672:70223] (null)-0x0-0
2023-02-18 15:20:32.003346+0800 TestCache[672:70223] (null)-0x0-1
2023-02-18 15:20:32.003359+0800 TestCache[672:70223] (null)-0x0-2
2023-02-18 15:20:32.003373+0800 TestCache[672:70223] (null)-0x0-3
2023-02-18 15:20:32.003542+0800 TestCache[672:70223] (null)-0x0-4
2023-02-18 15:20:32.003558+0800 TestCache[672:70223] (null)-0x0-5
2023-02-18 15:20:32.003571+0800 TestCache[672:70223] (null)-0x0-6
2023-02-18 15:20:32.003592+0800 TestCache[672:70223] study9-0xc5461a010283df10-7
2023-02-18 15:20:32.003606+0800 TestCache[672:70223] (null)-0x0-8
2023-02-18 15:20:32.003619+0800 TestCache[672:70223] (null)-0x0-9
2023-02-18 15:20:32.003633+0800 TestCache[672:70223] (null)-0x0-10
2023-02-18 15:20:32.003646+0800 TestCache[672:70223] (null)-0x0-11
2023-02-18 15:20:32.003660+0800 TestCache[672:70223] (null)-0x0-12
2023-02-18 15:20:32.003674+0800 TestCache[672:70223] (null)-0x0-13
2023-02-18 15:20:32.003688+0800 TestCache[672:70223] (null)-0x0-14
2023-02-18 15:20:32.003701+0800 TestCache[672:70223] (null)-0x0-15
2023-02-18 15:20:32.003715+0800 TestCache[672:70223] ***************

咱们看到_mask_occupied的改变是1-1,1-2,3-1,3-2,3-3,3-4,7-1,7-2,7-3,7-4,7-5,7-6,7-7,7-8,15-1

  • 开端是1-1的原因:真机环境初始化容量INIT_CACHE_SIZE界说为2,所以_mask=2-1=1
  • 真机环境CACHE_END_MARKER的值为0CACHE_ALLOW_FULL_UTILIZATION的值为1

类的底层探究-cache

结论:真机的初始化容量是2,在容量小于等于8的时分是满扩容,超过8的时分才会触发3/4扩容,这也就解说了_mask_occupied7-815-1改变的原因

总结

  • cache的巨细是16个字节,分别是8字节的指针_bucketsAndMaybeMask8字节的指针_originalPreoptCache
  • _bucketsAndMaybeMaskCACHE_MASK_STORAGE_OUTLINED的架构下存的便是buckets,其他架构会存mask(高16位或许低16位mask16ShiftBits
  • _mask=capacity-1 是cache的容量-1
  • _occupied是已缓存的办法数
  • _originalPreoptCache或许跟同享缓存或许是缓存的测验有关
  • 重点是cache的insert办法
  • 初始化INIT_CACHE_SIZE巨细的容量,此刻拓荒内存不必freeOld
  • 3/4或许7/8扩容(架构不同)
  • 2倍扩容,扩容是新拓荒内存,free掉本来的内存
  • 经过哈希函数hash_cache获取下标
  • 哈希抵触的解决是再哈希取下个下标
  • 为什么是哈希结构(假如是一般的数组结构每次办法判别存在与否需求O(n)的时刻复杂度,而用哈希数组能够在O(1)的时刻复杂度获取下标)
  • 3/4其实是负载因子的概念,值越大的状况空间利用率高,可是更简单哈希抵触,查找时刻变久;值越小,更快的需求进行拓荒新的内存空间,空间利用率低,当然哈希抵触概率减小,查找时刻变快。3/4是时刻和空间利用率都比较不错的
  • 真机的初始化容量是2,在容量小于等于8的时分是满扩容,超过8的时分才会触发3/4扩容