06-将手伸进objc_class中的cache, 看看我们调用

2020-09-20  本文已影响0人  luin4

  • 我们都知道OC中属性存储数据信息的, 方法的功能修改属性的数据.
  • 在前面我们分析过objc_class结构体(里面存储类的信息), 里面有继承过来的isa(指向元类), 有superClass, 有bits(存储属性, 实例方法, 代理, ro里有成员变量)结构体
  • cache结构体里面存储的是什么呢?

1: 我们先根据源码梳理下objc_class的结构图

objc_class结构树-c1342

2: 接下来我们来通过指针偏移试着看看cache里存储的是什么

cache查找LLDB流程, 图是月月的!

关于缓存占用量的计算,有以下几点说明:


3: 我们详细的看下cache的结构

struct cache_t {//只复制了部分重要信息
//CACHE_MASK_STORAGE_OUTLINED: 模拟器 or macOS环境
#if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
    // explicit_atomic: 原子性, 保证cache增删改差的线程安全
    // 等同于struct bucket_t * _buckets;
    // _buckets: 存放imp和sel
    explicit_atomic<struct bucket_t *> _buckets;
    explicit_atomic<mask_t> _mask; //掩码
//CACHE_MASK_STORAGE_HIGH_16: 64位真机
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
    // 真机环境中, buckets和mask掩码存储在一起, 掩码在高16位(通过 << maskShift), buckets 存在剩余位
    explicit_atomic<uintptr_t> _maskAndBuckets;
    mask_t _mask_unused;//暂时没有用到, 猜测没开发完, 不管它
    
    static constexpr uintptr_t maskShift = 48;
    
    //掩码后的其他位必须为零。 msgSend
    //利用这些附加位来构造值
    //在一条来自_maskAndBuckets的指令中`mask << 4`。
    static constexpr uintptr_t maskZeroBits = 4;
    
    // The largest mask value we can store.
    static constexpr uintptr_t maxMask = ((uintptr_t)1 << (64 - maskShift)) - 1;
    
    // 应用于`_maskAndBuckets`的掩码,以获取存储桶指针。
    static constexpr uintptr_t bucketsMask = ((uintptr_t)1 << (maskShift - maskZeroBits)) - 1;
    
    // 确保我们有足够的位用于存储桶指针。
    static_assert(bucketsMask >= MACH_VM_MAX_ADDRESS, "Bucket field doesn't have enough bits for arbitrary pointers.");
//非64为真机, 因为iOS9之后废弃32位, 所以我们不研究它
#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_LOW_4
    // _maskAndBuckets stores the mask shift in the low 4 bits, and
    // the buckets pointer in the remainder of the value. The mask
    // shift is the value where (0xffff >> shift) produces the correct
    // mask. This is equal to 16 - log2(cache_size).
    explicit_atomic<uintptr_t> _maskAndBuckets;
    mask_t _mask_unused;

    static constexpr uintptr_t maskBits = 4;
    static constexpr uintptr_t maskMask = (1 << maskBits) - 1;
    static constexpr uintptr_t bucketsMask = ~maskMask;
#else
#error Unknown cache mask storage type.
#endif

#if __LP64__
    uint16_t _flags;
#endif
    uint16_t _occupied;

public:
    static bucket_t *emptyBuckets();
    //重点可以获取buckets列表
    struct bucket_t *buckets();
    mask_t mask();// 获取我们的掩码(也可以理解为开辟最大空间)
    mask_t occupied();// 记录当前缓存的方法数量
    void incrementOccupied();// 操作`occupied++`, 即新插入一个bucket
    void setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask);
    void initializeToEmpty();

    unsigned capacity();// 容量
    
    static struct bucket_t * endMarker(struct bucket_t *b, uint32_t cap);
    // 重新开辟空间, 一般在内存满3/4时扩容后调用
    void reallocate(mask_t oldCapacity, mask_t newCapacity, bool freeOld);
    // 插入新的bucket
    void insert(Class cls, SEL sel, IMP imp, id receiver);


4: 总结: 我们来梳理下cache的工作流程

cache 缓存bucket流程图

疑问解答 --Style_月月

cache_next实现-c739
cache缓存bucket流程图.jpg
上一篇下一篇

猜你喜欢

热点阅读