类 の cache_t

312 阅读1分钟

1. cache_t & bucket_t 结构

struct cache_t {
    struct bucket_t *_buckets;  // 桶结构[结构体],保存缓存 method_t 列表的数据结构
    mask_t _mask;               // 当前缓存桶结构的大小
    mask_t _occupied;           // 当前缓存方法数量

// ------- 方法 ----------
public:
    struct bucket_t *buckets();
    mask_t mask();
    mask_t occupied();
    void incrementOccupied();
    void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
    void initializeToEmpty();

    mask_t capacity();
    bool isConstantEmptyCache();
    bool canBeFreed();

    static size_t bytesForCapacity(uint32_t cap);
    static struct bucket_t * endMarker(struct bucket_t *b, uint32_t cap);

    void expand();
    void reallocate(mask_t oldCapacity, mask_t newCapacity);
    struct bucket_t * find(SEL sel, id receiver);

    static void bad_cache(id receiver, SEL sel, Class isa) __attribute__((noreturn));
};

struct bucket_t {
private:
    // IMP-first is better for arm64e ptrauth and no worse for arm64.
    // SEL-first is better for armv7* and i386 and x86_64.
#if __arm64__
    uintptr_t _imp; // 方法 IMP
    SEL _sel;       // 方法 SEL 对应 key
#else
    SEL _sel;
    uintptr_t _imp;
#endif
};

2. 查找方法缓存时机

在调用 objc_msgSend 方法的之前会调用 getCache 方法从 cache_t 中的缓存 bucket 列表中查找,如果存在缓存直接返回缓存 IMP 实现,否则走正常的方法查找流程。

3. 缓存组合结构

  • 缓存方法存储桶结构 bucket_t
  • 缓存结构容量 capacity = mask + 1
  • 当前占用容量 occupied

组合结构图

4. 缓存策略

  • 默认容量 capacity = 4
  • 当占用超过容量的 3/4 时需要扩容为当前容量的两倍, 采用3/4的节点是为了提前扩容,保证容量够存储,否则到了临界点扩容容易溢出或者造成其他问题
  • 重新申请容量为两倍的缓存结构内存,释放掉之前的内存,然后缓存当前正在调用的方法
  • 方法存储通过 cache_hash 方法哈希 SEL & mask 得到的哈希值对应方法,find 查找过程也是通过该哈希值key,采用开放寻址算法快速查找

5. 缓存流程

缓存流程