前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >LLDB结合底层源码分析Cache数据结构

LLDB结合底层源码分析Cache数据结构

作者头像
CC老师
发布2022-01-14 14:52:56
3070
发布2022-01-14 14:52:56
举报

我再来分享一个底层知识点,学到了之后不写出来总觉得不是自己的,关于cache的数据结构,首先cache是什么呢?

这个英文单词就是缓存的意思,那他缓存的是什么呢?我们大多数人肯定都不太了解,我之前获取bits,可以进行内存平移,那我获取cache是不是也可以进行内存平移呢?

一试便知,我在objc的源码工程里面写了一个demo,自定义了一个类 LGPerson 继承自 NSObject,来到main里面,通过 class 拿到这个类,然后在下一行打一个断点,如下图。

运行,停在断点处之后,我来进行万能的LLDB调试。

拿到 pClass 的地址之后给他打印出来,但是直接打印是不行的,还要进行一下强转。

强转之前,我先给他平移16个字节,就是加10,变成了0x0000000100008460,然后强转的话,转成什么类型呢?

就是 cache 的类型,那 cache 是什么类型我不记得了,我就去源码里面找一下,全局搜索objc_class。

可以在后面加一个空格,结果会少很多,找到 new.h结尾的文件,然后里面就有这个 objc_class 结构体,点进去。

这里就找到了cache,这个过程需要对底层原理有比较好的掌握,cache 是什么类型就一目了然了,是一个cache_t 类型,我拷贝出来,加个星号表示还原他的指针。

回车就得到了 cache_t 类型的 $1,然后我来看里面的数据。

打印得到了这么一长串内容,主要有这么几个变量名:_bucketsAndMaybeMask、_maybeMask、_flags、_occupied、_originalPreoptCache。

那这些东西我看不懂,不知所云,所以我需要在源码里面找到对应的说辞,怎么找呢,我 command 点击 cache_t,Jump to Definition。

很明显,cache_t 也是一个结构体,然后有一个private,里面就有这个 _bucketsAndMaybeMask 等一些变量。

跟我打印出来的一模一样,除了 _bucketsAndMaybeMask之外,其他几个都被 union 一个大括号包进去了,他们是一个联合体。

很多人可能对于这种结构不那么了解,我再来补充一个点,在真机上的app,是运行在 arm64 架构上的,模拟器呢?i386,Mac呢?

x86_64,M1 的 Mac 也是 arm64,这是跟硬件有关的,那这个联合体里面有一个 #if __LP64__ 是什么呢?__LP64__ 就是适用在 Linux 和 macOS 电脑上面的一个数据模型,我找了个表格给大家看一下。

就很明显了,__LP64__ 就是指代 Unix 系列的操作系统,所以都是跑的64位,也就是说,这个 if 条件是成立的。

整个 cache_t 的数据结构就能够很清晰很直观的了解了,那么问题来了,cache是缓存,那到底缓存什么呢?要么缓存属性,要么缓存方法,这里我看到了属性,但是没看到方法。

按理说也应该缓存方法才对,如果是缓存方法的话,我应该在这个结构体里面能看到 sel 和 imp,但是并没有,是不是意味着他不是缓存这些东西呢?我先卖个关子。

接下来又有一个问题,这几个属性里面,哪一个才是我们需要关注的、最重要的那个?打印信息里面两个没有值的可以排除,剩下的我也不知道哪个最重要,那怎么办呢?

这里又有一个阅读源码的小技巧,就是看他提供的功能方法,这个cache_t,是一个缓存,也就必定是一个存储的过程,意味着他一定会有东西进行了读写,或者增删改查等等的操作。

所以,我再继续往下找方法,在481行就找到了一个 insert,也就是插入,正好命中了我刚刚的猜想,他离不开增删改查,并且他的参数正好就有 sel 和 imp。

所以,我来看看他里面有没有我想要的东西,点进去,看到了两个 sel(),都是由 bucket_t 对象中的元素进行调用,也就是对 bucktet_t 进行了一些操作,难道关键就在bucket_t ?(下图源码进行了一些删减)

正好在之前的 cache_t 结构体中找 insert 的时候也看到了不少 bucket_t。

感觉他的重心应该就是这个bucket_t,我直接点进去,看到如下图的内容。

这就恍然大明白了,就是千呼万唤的 imp 和 sel,bucket 单词是“桶”的意思,就是一个容器,装了很多的imp 和 sel,并且一个 imp 就对应了一个 sel,梳理一下。

cache 里面有一个 buckets,buckets 里面就会有一个 sel 和 imp,但是这个具体的结构,我还不是非常的清楚,但是知道这么多就已经足够了。

然后我要去验证里面的值,是不是真的有,是不是真的是这样的呢?眼见不一定为实,自己操作一遍才放心,那我继续LLDB调试。

之前已经拿到了$2,然后他的重点是buckets,所以我是不是应该打印这个_bucketsAndMaybeMask 呢?只有这个里面有 buckets 这个词,试一试。

然后我去拿他的Value,因为也没其他东西可以拿。

竟然拿不到!又进了死胡同,LLDB调试不出来了,怎么办?这个时候又回到了上面提到的调试技巧,我只能去找他有没有合适的方法。

这是LLDB调试遇到问题的时候最常见的办法,那我去 cache_t 结构体中找一下是不是有get相关的方法,别说,还真有。

这里得到了一个结构体指针 buckets,感觉事情变得简单了,我拷贝 buckets() 继续进行调试。

果真拿到了一个 bucket_t 的地址,那这个地址里面是什么我也不知道,打印出来看一下。

跟之前的源码分析一模一样,就是 imp 和 sel,但是他们什么都没有,很尴尬,不过也没关系,我这里已经可以得到一些信息了,bucket_t 结构体里面是有一个 #if 判断的。

这个条件语句里面,我是走的 if 还是 else 呢,我都不用分析这个条件,对比一下打印出来的 $4 就知道了,先 imp,然后 sel,所以走的是 __arm64__,大多数人在这里应该都是走的 else,为什么呢?

因为我是M1的Mac,我已经走在了时尚的最前沿,哈哈哈,大多数人都是 x86,所以走的是 else,如果是真机环境的话,走的也是 __arm64__,其实区别不大,了解一下就好了。

但是他们为什么都没有呢?因为没有调用方法!没有调用方法,他有个LLDB的缓存啊,那我再来调用一下方法,这个 LGPerson 我已经写好了一个实例方法 saySomething。

调完方法之后,上面的流程我再来一次。

imp 的 Value 不出所料有值了!但是你们操作的时候,可能还是会没有东西,如果你们没有的话,怎么办呢?

我也提一嘴,这是一个 buckets,他有个s字母结尾,就意味着他是一个数组,所以你可以在后面加上一个[1],取他下一个bucket,或许你就有值了。

如果没有多个就可以直接取,这里涉及到了哈希函数,因为哈希函数的下标是不一定的,普通的数组是从零开始的,但是哈希就不同,而且他还是无序的。

但是这个 $10 还不是我想看到的结果,我想看的是最终打印出 saySomething,才能证明我们的源码分析没有问题,那我还是同样的来看 bucket_t 结构体里面有没有相应的方法。

找到一个 sel(),不解释了,直接拿过来用。

打印出了 saySomething,就这?简单得很嘛,所以,我也应该同样的可以改成 imp()。

竟然报错了,问题不大,这个错误提示很熟悉,翻译过来就是参数太少了,预想的是有2个参数,但是我没有给,只有0个,如果你也这么操作了,说明你肯定没有去仔细看源码,imp() 就在 sel() 下面一点点。

这里他需要两个参数,一个 bucket_t,一个 class,这个 class 我可以给你,很简单,就是 pClass,那这个bucket_t 我怎么给?我不知道,我也不想知道,感觉很麻烦的亚子,那我直接丢个 nil,回车。

漂亮,来自 KCObjcBuild 里面的 LGPerson 的实例方法 saySomething,完美打印出来,到这里,cache的数据结构分析,就基本搞定,到此结束。

最后呢,如果对于文章内容有任何疑问都可以进行留言,objc源码我就不放了,网上一大把,如果某些内容有误也恳请帮我指出来,共同进步。

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

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

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

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

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