iOS进阶之底层原理-cache_t

接着上一篇的对象结构探索,我们详细介绍cache_t。源码为最新的objc4-818.2。

cache_t的底层结构

struct cache_t {
// 省略一堆私有属性,方法
public:
    // The following four fields are public for objcdt's use only.
    // objcdt reaches into fields while the process is suspended
    // hence doesn't care for locks and pesky little details like this
    // and can safely use these.
    unsigned capacity() const;
    struct bucket_t *buckets() const;
    Class cls() const;

    mask_t occupied() const;
    void initializeToEmpty();

    void insert(SEL sel, IMP imp, id receiver);
    void copyCacheNolock(objc_imp_cache_entry *buffer, int len);
    void destroy();
    void eraseNolock(const char *func);
};

mask_t cache_t::occupied() const
{
    return _occupied;
}
unsigned cache_t::capacity() const
{
    return mask() ? mask()+1 : 0; 
}

Class cache_t::cls() const
{
    return (Class)((uintptr_t)this - offsetof(objc_class, cache));
}
struct bucket_t *cache_t::buckets() const
{
    uintptr_t addr = _bucketsAndMaybeMask.load(memory_order_relaxed);
    return (bucket_t *)(addr & bucketsMask);
}

核心逻辑就在增加方法的时候,现在是insert方法。

void cache_t::insert(SEL sel, IMP imp, id receiver)
{
    // Use the cache as-is if until we exceed our expected fill ratio.
// 获取实际容量再加1
    mask_t newOccupied = occupied() + 1;
// 获取总容量
    unsigned oldCapacity = capacity(), capacity = oldCapacity;
    if (slowpath(isConstantEmptyCache())) {// 如果为空,那么创建一个初始化的cache,
        // Cache is read-only. Replace it.
        // INIT_CACHE_SIZE为4
        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.
    }
// 这是最新的代码,允许缓存总大小比较小的时候 可以百分百利用,不去创建多余的空间
// FULL_UTILIZATION_CACHE_SIZE 为8 arm64 CACHE_END_MARKER为0 也就是小于8的可以占满空间
    else if (capacity <= FULL_UTILIZATION_CACHE_SIZE && newOccupied + CACHE_END_MARKER <= capacity) {
        // Allow 100% cache utilization for small buckets. Use it as-is.
    }
    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 {// 清空sel为空的缓存
        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
}
void cache_t::reallocate(mask_t oldCapacity, mask_t newCapacity, bool freeOld)
{
    bucket_t *oldBuckets = buckets();
    bucket_t *newBuckets = allocateBuckets(newCapacity);

    setBucketsAndMask(newBuckets, newCapacity - 1);
    
    if (freeOld) {
        collect_free(oldBuckets, oldCapacity);
    }
}
  • 首先判断曾经是否是空缓存,再判断是否曾经创建过,没有创建过的初始化大小为4的容量
  • 如果新增后,大小小于四分之三,或者8分之7,直接增加
  • 反之,扩容,扩容为两倍大小,如果愿容量为0,则扩容为初始化大小4,如果扩容后的大小超过最大的容量1左移16位就是65536,则容量为最大容量65536
  • 插入新的方法到buckets内,调用bucket_t内的set方法,存储在私有变量_sel数组和_imp数组中
  • reallocate每次调用完都会清空之前的缓存

  • static inline mask_t cache_hash(SEL sel, mask_t mask) 
    {
        uintptr_t value = (uintptr_t)sel;
        return (mask_t)(value & mask);
    }

    bucket_t的结构为

    struct bucket_t {
    private:
        explicit_atomic<uintptr_t> _imp;
        explicit_atomic<SEL> _sel;
    
    public:
        template <Atomicity, IMPEncoding>
        void set(bucket_t *base, SEL newSel, IMP newImp, Class cls);
    }
    template<Atomicity atomicity, IMPEncoding impEncoding>
    void bucket_t::set(bucket_t *base, SEL newSel, IMP newImp, Class cls)
    {
    
        // objc_msgSend uses sel and imp with no locks.
        // It is safe for objc_msgSend to see new imp but NULL sel
        // (It will get a cache miss but not dispatch to the wrong place.)
        // It is unsafe for objc_msgSend to see old imp and new sel.
        // Therefore we write new imp, wait a lot, then write new sel.
        
        uintptr_t newIMP = (impEncoding == Encoded
                            ? encodeImp(base, newImp, newSel, cls)
                            : (uintptr_t)newImp);
    
        if (atomicity == Atomic) {
            _imp.store(newIMP, memory_order_relaxed);
            
            if (_sel.load(memory_order_relaxed) != newSel) {
                mega_barrier();
                _sel.store(newSel, memory_order_relaxed);
            }
        } else {
            _imp.store(newIMP, memory_order_relaxed);
            _sel.store(newSel, memory_order_relaxed);
        }
    }

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值