前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS方法缓存cache详解

iOS方法缓存cache详解

作者头像
CC老师
发布2022-01-14 15:00:23
2970
发布2022-01-14 15:00:23
举报
文章被收录于专栏:HelloCode开发者学习平台

写在开头:我最近看到网上很多关于方法缓存这方面的文章或多或少都存在一些错误,或者说阐述的不是那么的完整。我写这篇文章的目的是为了看到这篇文章的各位iOS开发者能够对iOS中的方法缓存策略能有一个正确且全面的了解。下面是正文。

在iOS中,对象方法是存储在类对象的bits里面,类方法是存储在元类对象的bits里面。类对象和元类对象的本质都为objc_class类型的结构体。

objc_class数据结构如下:

大家可以看到,这个objc_classj结构体里面有个cache。这个cache的用途就是,缓存我们调用过的方法。

比如我们通过p对象及LGPerson分别调用了test1和test2方法,那么test1方法就会缓存到LGPerson类对象的cache当中,test2方法就会缓存到LGPerson的元类对象的cache当中。

方法的缓存基于不同架构,缓存策略是不一样的。以下是方法存储的核心代码的部分截图,这里就体现了在不同架构下的不同的缓存策略。

下面是对这部分代码的详细解读:

occupied()函数的作用就是获取当前容器已经缓存的方法的个数。

capacity()函数的作用就是获取当前容器能够缓存方法的最大个数,也就是容器的长度。

INIT_CACHE_SIZE在arm64架构下为2,在x86_64架构下为4。

代码语言:javascript
复制
if (slowpath(isConstantEmptyCache())) {
        // Cache is read-only. Replace it.
        if (!capacity) capacity = INIT_CACHE_SIZE;
        reallocate(oldCapacity, capacity, /* freeOld */false);
}

(滑动显示更多)

上面这部分的代码的意思是:当cache中缓存方法的容器为空时,在arm64架构下初始化容器的长度为2,在x84_64架构下初始化容器的长度为4。

CACHE_END_MARKER在x86_64架构下为1,在arm64架构下为0。

cache_fill_ratio(capacity)函数在x86_64架构下为容器长度的3/4,在arm64架构下为容器长度的7/8。

这里需要注意的一个点就是CACHE_END_MARKER在不同架构下的值是不一样的。

代码语言:javascript
复制
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.
    }

(滑动显示更多)

所以上面这部分的代码的意思为:在x86_64架构下,实际存储的方法的个数小于等于容器的总容量的3/4再减1时,啥也不干。在arm64架构下,实际存储的方法的个数小于等于容器的总容量的7/8时,啥也不干。

CACHE_ALLOW_FULL_UTILIZATION在arm64架构下为1。

FULL_UTILIZATION_CACHE_SIZE为8。

代码语言:javascript
复制
#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

(滑动显示更多)

上面部分代码的意思是:在arm64架构下,当容器的长度小于或等于8时,实际存储的方法的个数小于或等于容器的长度的时候,啥也不干。

代码语言:javascript
复制
else {
        capacity = capacity ? capacity * 2 : INIT_CACHE_SIZE;
        if (capacity > MAX_CACHE_SIZE) {
            capacity = MAX_CACHE_SIZE;
        }
        reallocate(oldCapacity, capacity, true);
    }

(滑动显示更多)

总结

所以,综合上面的代码的出来的结论就是:

  • 在arm64结构,也就是真机环境下,刚开始初始化的缓存方法的容器的长度2,当容器的长度小于8时,是满容量了才扩容。当容器的长度大于8时,是7/8扩容。也就是说当容器的长度为8时,容器可以存储8个方法。当容器的长度为16时,当第15个方法需要存储进来的时候,容器就要扩容了。
  • 在x86_64架构下,刚开始初始化的容器的长度为4,是3/4扩容。这里的3/4扩容指的是:如果容器的长度为4,当第3个数据需要存储的时候,就要扩容了。如果容器的长度为8,当第6个数据需要存储的时候,就要扩容了。也就是说容器只能存储容器长度的3/4减1个方法。

还有一点就是:当容器扩容之后,前面存储的方法也会随之清空。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-11-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 HelloCoder全栈小集 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档