美文网首页
iOS-OC 方法缓存机制(cache_t)

iOS-OC 方法缓存机制(cache_t)

作者: 洧中苇_4187 | 来源:发表于2020-05-08 16:20 被阅读0次

一,首先让我们看看类的结构 image.png

除了具体的类信息,还有一个重要的结构-->方法缓存cache,本文就是说明它的运行机制.

方法缓存的结构如下 image.png

1> 方法缓存里有三个属性:
1.1 bucket_t维护着一个散列表,里面的元素是以方法名"SEL"为key,方法的实现"IMP"为value的字典,
1.2 _mask 它代表的是散列表的长度-1,最初分配的值是4, 它的作用是 传入的方法名SEL & _mask得到的这个值,就是方法保存的位置,
1.3 _occupied已经缓存的方法数量,它的数量<= 3/4 * _mask,否则_mask会扩容为原来的两倍,直到<= (1<<16)

下面来看看它里面的判断逻辑是怎么样的
主要代码在这个位置

image.png
void cache_t::insert(Class cls, SEL sel, IMP imp, id receiver)
{
    mask_t newOccupied = occupied() + 1;  插入新的方法缓存,数量+1
    unsigned oldCapacity = capacity(), capacity = oldCapacity;
    if (slowpath(isConstantEmptyCache())) {如果还没有缓存过方法
        // Cache is read-only. Replace it.
        if (!capacity) capacity = INIT_CACHE_SIZE; 这是一个容量为4的宏,最初分配的容量就是4
        reallocate(oldCapacity, capacity, /* freeOld */false);创建-分配内存
    }
    else if (fastpath(newOccupied <= capacity / 4 * 3)) {
        保证缓存表存的方法数小于等于 容量的3/4 
    }
    else {超过容量的3/4,容量翻倍
        capacity = capacity ? capacity * 2 : INIT_CACHE_SIZE;
        if (capacity > MAX_CACHE_SIZE) {不能超过最大值,最大值是1<<16
            capacity = MAX_CACHE_SIZE;
        }
        超过容量后,将之前缓存的方法全部清空 "true"
        reallocate(oldCapacity, capacity, true);
    }

    bucket_t *b = buckets();
    mask_t m = capacity - 1;
    mask_t begin = cache_hash(sel, m); 
    mask_t i = begin; 通过 sel & mask 计算出sel该存放的位置 "i"
    如果计算出来的值没有缓存方法,则直接插入,保存;
    如果已经有方法插入了,在__arm64__架构 i--(其他架构i++),即,如果被占用,往上走一格,还被占用继续往上走,
因为规则限定了3/4,所以肯定能找到没有保存方法的位置.
    do {
        if (fastpath(b[i].sel() == 0)) {
            incrementOccupied();
            b[i].set<Atomic, Encoded>(sel, imp, cls);  保存方法
            return;
        }
        if (b[i].sel() == sel) {
        这种情况是其他线程,已经把方法添加到这里了,那就直接退出循环
            return;
        }
    } while (fastpath((i = cache_next(i, m)) != begin)); "i"不等于初始位置 i--,继续循环.

说明:
1> 方法的存储并不是按照数组一样从上到下存储,而是通过 sel & mask来存储的,所以难免会存在内存利用率低,但是加快了方法查找的速度,即:空间换时间.

2> 方法缓存是先于isa的方法查找,就是说,缓存中找不到,再到自己的方法列表中查找,找到之后也会缓存到cache_t中,如果是父类的方法,也是会缓存到自己的表当中的.

3> arm64 之后增加了很多 &mask的操作,获取具体的类信息,也是通过 bits & mask 来获取,里面存储的信息更多了(文中提到的mask 不同的地方,mask的值是不同的).

4> 如果cache_next(i,m)循环到0,还未找到,赋值i == mask,继续循环,直到i == begin,证明没有缓存这个方法,这是最差的情况,相当于遍历了一遍数组.

相关文章

  • iOS-OC 方法缓存机制(cache_t)

    一,首先让我们看看类的结构image.png 除了具体的类信息,还有一个重要的结构-->方法缓存cache,本文就...

  • objc_class中的cache_t

    目标 主要分析cache_t流程,对象的属性、方法都会被iOS的缓存机制缓存下来,下次调用会从缓存中查找,缓存的功...

  • 方法缓存Cache_t分析

    缓存Cache_t bucket_t cache_t 缓存的是 方法 method_t: 缓存流程 缓存的入口是:...

  • iOS-底层原理07-catch_t

    对象的内存结构 cache_t结构 1.第一次运行一个方法之前,cache_t缓存中的方法为0,之后缓存中的方法的...

  • 底层11:Runtime-method、方法缓存、散列表

    方法缓存:Class内部结构中有个方法缓存(cache_t),用散列表来缓存曾经调用过的方法,可以提高方法的查找速...

  • iOS 方法缓存机制cache_t

    类对象的数据结构 其中cache_t就是方法缓存,用散列表缓存曾今调用过的方法 缓存查找方法在:源码的objc-c...

  • 探究 cache_t (方法缓存)的本质

    Class 内部中有个方法缓存 cache_t,用散列表来缓存调用过的方法,可以提高访问方法的速度。 一、cach...

  • ios方法缓存

    ?Class内部结构中有个方法缓存(cache_t),用散列表(哈希表)来缓存曾经调用过的方法,可以提高方法的查找...

  • Runtime底层解析 - 方法缓存 :cache

    Class内部结构中有个方法缓存(cache_t),用散列表(哈希表)来缓存曾经调用过的方法,可以提高方法的查找速...

  • Runtime 之 Class结构

    Class的结构 Class内部结构中有个方法缓存(cache_t),用散列表(哈希表)来缓存曾经调用过的方法,可...

网友评论

      本文标题:iOS-OC 方法缓存机制(cache_t)

      本文链接:https://www.haomeiwen.com/subject/prvfnhtx.html