区块链技术博客
www.b2bchain.cn

大师重磅内容(14)-cache 底层分析求职学习资料

本文介绍了大师重磅内容(14)-cache 底层分析求职学习资料,有助于帮助完成毕业设计以及求职,是一篇很好的资料。

对技术面试,学习经验等有一些体会,在此分享。

思路:决定一个类功能的是函数,所以从cache_t的函数中去寻找突破口。

cache_t结构体中,有一个方法void incrementOccupied();,增加占用,内部实现为:_occupied++;,很容易理解:向cache_t中插入内容,占用数加1
全局搜索incrementOccupied()方法,只有一个地方用到了该方法,向cache_t中插入数据,cache_t::insert方法。参数有:方法编号sel,方法实现地址指针imp,消息接受者。见下图:

大师重磅内容(14)-cache 底层分析

继续全局搜索cache_t::insert方法找到了一段非常重要的注释,解读注释:cache_t分为cache读取和cache写入两个点。见下图:

大师重磅内容(14)-cache 底层分析

通过注释可以了解,objc_msgSendcache_getImp会进行缓存数据的读取,cache_t::insert会进行缓存数据的插入创建。

要想解决上面留下的问题,肯定要从创建插入的流程进行探索!

insert方法研究

cache_t::insert方法关键步骤,见下图。整体可以分为两个部分:

  • 第一步进行容器的初始化工作
  • 第二步进行数据插入。

大师重磅内容(14)-cache 底层分析

下面详细解读insert流程。

  • 1.容器初始化

设置断点,确保调用sayHello1方法进入断点,lldb输出当前类clsLGHuman,方法编号selsayHello1。见下图:

大师重磅内容(14)-cache 底层分析

调用occupied()方法,lldb调试输出可发现,当前占用数为0,新的占用数newOcuupied = 1;可以理解初次插入,当前容器占用为空。所以首次进入缓存为空,会进行容器的创建!见下图

大师重磅内容(14)-cache 底层分析

默认初始化容量:4,即1 << INIT_CACHE_SIZE_LOG2 (1<<2),然后调用reallocate()方法进行初始化。见下图:

大师重磅内容(14)-cache 底层分析

setBucketsAndMask中,会对内存空间进行开辟,同时设置当前_occupied = 0。见下面源码:

#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16 || CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16_BIG_ADDRS  void cache_t::setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask) {     uintptr_t buckets = (uintptr_t)newBuckets;     uintptr_t mask = (uintptr_t)newMask;      ASSERT(buckets <= bucketsMask);     ASSERT(mask <= maxMask);      _bucketsAndMaybeMask.store(((uintptr_t)newMask << maskShift) | (uintptr_t)newBuckets, memory_order_relaxed);     _occupied = 0; }

从上面的源码中可以看出,_bucketsAndMaybeMask中存储的内容,是newMasknewBucketsnewMask是容量减1newBuckets是新开辟的内存空间地址。

  • 2.数据插入

容器完成初始化后,进行首次数据插入前,occupied()占用数还为0。见下图:

大师重磅内容(14)-cache 底层分析

初始化mask为当前容量减1,即mask = capacity - 1;,并通过cache_hash方法进行hash运算,sel & mask,获取哈希下标,即sel存储下标。hash下标算法源码:

“`c
static inline mask_t cache_hash(SEL sel, mask_t mask)
{
return (mask_t)(uintptr_t)sel & mask;

思路:决定一个类功能的是函数,所以从cache_t的函数中去寻找突破口。

cache_t结构体中,有一个方法void incrementOccupied();,增加占用,内部实现为:_occupied++;,很容易理解:向cache_t中插入内容,占用数加1
全局搜索incrementOccupied()方法,只有一个地方用到了该方法,向cache_t中插入数据,cache_t::insert方法。参数有:方法编号sel,方法实现地址指针imp,消息接受者。见下图:

大师重磅内容(14)-cache 底层分析

继续全局搜索cache_t::insert方法找到了一段非常重要的注释,解读注释:cache_t分为cache读取和cache写入两个点。见下图:

大师重磅内容(14)-cache 底层分析

通过注释可以了解,objc_msgSendcache_getImp会进行缓存数据的读取,cache_t::insert会进行缓存数据的插入创建。

要想解决上面留下的问题,肯定要从创建插入的流程进行探索!

insert方法研究

cache_t::insert方法关键步骤,见下图。整体可以分为两个部分:

  • 第一步进行容器的初始化工作
  • 第二步进行数据插入。

大师重磅内容(14)-cache 底层分析

下面详细解读insert流程。

  • 1.容器初始化

设置断点,确保调用sayHello1方法进入断点,lldb输出当前类clsLGHuman,方法编号selsayHello1。见下图:

大师重磅内容(14)-cache 底层分析

调用occupied()方法,lldb调试输出可发现,当前占用数为0,新的占用数newOcuupied = 1;可以理解初次插入,当前容器占用为空。所以首次进入缓存为空,会进行容器的创建!见下图

大师重磅内容(14)-cache 底层分析

默认初始化容量:4,即1 << INIT_CACHE_SIZE_LOG2 (1<<2),然后调用reallocate()方法进行初始化。见下图:

大师重磅内容(14)-cache 底层分析

setBucketsAndMask中,会对内存空间进行开辟,同时设置当前_occupied = 0。见下面源码:

#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16 || CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16_BIG_ADDRS  void cache_t::setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask) {     uintptr_t buckets = (uintptr_t)newBuckets;     uintptr_t mask = (uintptr_t)newMask;      ASSERT(buckets <= bucketsMask);     ASSERT(mask <= maxMask);      _bucketsAndMaybeMask.store(((uintptr_t)newMask << maskShift) | (uintptr_t)newBuckets, memory_order_relaxed);     _occupied = 0; }

从上面的源码中可以看出,_bucketsAndMaybeMask中存储的内容,是newMasknewBucketsnewMask是容量减1newBuckets是新开辟的内存空间地址。

  • 2.数据插入

容器完成初始化后,进行首次数据插入前,occupied()占用数还为0。见下图:

大师重磅内容(14)-cache 底层分析

初始化mask为当前容量减1,即mask = capacity - 1;,并通过cache_hash方法进行hash运算,sel & mask,获取哈希下标,即sel存储下标。hash下标算法源码:

“`c
static inline mask_t cache_hash(SEL sel, mask_t mask)
{
return (mask_t)(uintptr_t)sel & mask;

思路:决定一个类功能的是函数,所以从cache_t的函数中去寻找突破口。

cache_t结构体中,有一个方法void incrementOccupied();,增加占用,内部实现为:_occupied++;,很容易理解:向cache_t中插入内容,占用数加1
全局搜索incrementOccupied()方法,只有一个地方用到了该方法,向cache_t中插入数据,cache_t::insert方法。参数有:方法编号sel,方法实现地址指针imp,消息接受者。见下图:

大师重磅内容(14)-cache 底层分析

继续全局搜索cache_t::insert方法找到了一段非常重要的注释,解读注释:cache_t分为cache读取和cache写入两个点。见下图:

大师重磅内容(14)-cache 底层分析

通过注释可以了解,objc_msgSendcache_getImp会进行缓存数据的读取,cache_t::insert会进行缓存数据的插入创建。

要想解决上面留下的问题,肯定要从创建插入的流程进行探索!

insert方法研究

cache_t::insert方法关键步骤,见下图。整体可以分为两个部分:

  • 第一步进行容器的初始化工作
  • 第二步进行数据插入。

大师重磅内容(14)-cache 底层分析

下面详细解读insert流程。

  • 1.容器初始化

设置断点,确保调用sayHello1方法进入断点,lldb输出当前类clsLGHuman,方法编号selsayHello1。见下图:

大师重磅内容(14)-cache 底层分析

调用occupied()方法,lldb调试输出可发现,当前占用数为0,新的占用数newOcuupied = 1;可以理解初次插入,当前容器占用为空。所以首次进入缓存为空,会进行容器的创建!见下图

大师重磅内容(14)-cache 底层分析

默认初始化容量:4,即1 << INIT_CACHE_SIZE_LOG2 (1<<2),然后调用reallocate()方法进行初始化。见下图:

大师重磅内容(14)-cache 底层分析

setBucketsAndMask中,会对内存空间进行开辟,同时设置当前_occupied = 0。见下面源码:

#elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16 || CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16_BIG_ADDRS  void cache_t::setBucketsAndMask(struct bucket_t *newBuckets, mask_t newMask) {     uintptr_t buckets = (uintptr_t)newBuckets;     uintptr_t mask = (uintptr_t)newMask;      ASSERT(buckets <= bucketsMask);     ASSERT(mask <= maxMask);      _bucketsAndMaybeMask.store(((uintptr_t)newMask << maskShift) | (uintptr_t)newBuckets, memory_order_relaxed);     _occupied = 0; }

从上面的源码中可以看出,_bucketsAndMaybeMask中存储的内容,是newMasknewBucketsnewMask是容量减1newBuckets是新开辟的内存空间地址。

  • 2.数据插入

容器完成初始化后,进行首次数据插入前,occupied()占用数还为0。见下图:

大师重磅内容(14)-cache 底层分析

初始化mask为当前容量减1,即mask = capacity - 1;,并通过cache_hash方法进行hash运算,sel & mask,获取哈希下标,即sel存储下标。hash下标算法源码:

“`c
static inline mask_t cache_hash(SEL sel, mask_t mask)
{
return (mask_t)(uintptr_t)sel & mask;

部分转自互联网,侵权删除联系

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » 大师重磅内容(14)-cache 底层分析求职学习资料
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们