32 | 热点问题答疑(三)
下载APP
关闭
渠道合作
推荐作者
32 | 热点问题答疑(三)
2019-05-23 戴铭 来自北京
《iOS开发高手课》
课程介绍
讲述:冯永吉
时长09:37大小8.79M
你好,我是戴铭。
这是我们《iOS 开发高手课》专栏的第三期答疑文章,我将继续和你分享大家在学习前面文章时遇到的最普遍的问题。
今天,我在这段时间的留言问题中,挑选了几个 iOS 开发者普遍关注的问题,在这篇答疑文章里来做一个统一回复。
A/B 测试 SDK
最近一直在找一个好的 A/B 测试的 SDK,不知道作者之前用过什么好的 A/B 测试的 SDK(三方的,可以后台控制的)
我认为带后台功能的 A/B 测试 SDK 没什么必要,原因有二:
A/B 测试本身就是为业务服务的,需要对会影响产品决策的业务场景做大量定制化开发;
A/B 测试功能本身并不复杂,第三方后台定制化开发,成本也不会节省多少。
因此,我推荐后台功能自己来做,端上使用我在第 24 篇文章中提到的 SkyLab 就完全没有问题了。另外,SkyLab 也可以很方便地集成到你自己的后台中。
如何衡量性能监控的优劣?
对于性能的监控有没有衡量标准,如何衡量优劣?
我觉得,如果给所有 App 制定相同的衡量标准是不现实的,这样的标准,也是无法落地的。为什么这么说呢,很有可能由于历史原因或者 App 的特性决定了有些 App 的性能无法达到另一个 App 的标准。又或者说,有些 App 需要进行大量的重构,才能要达到另一个 App 的性能标准,而这些重构明显不是一朝一夕就能落地执行的。特别是业务还在快跑的情况下,你只能够有针对性地去做优化,而不是大量的重构。
回到性能监控的初衷,它主要是希望通过监控手段去发现突发的性能问题,这也是我们再做线上性能监控时需要重点关注的。
对于 App 运行普遍存在的性能问题,我们应该在上线前就设法优化完成。因为,线下的性能问题是可控的,而线上的性能问题往往是“摸不着”的,也正是这个原因,我们需要监控线上性能问题。
因此,性能监控的标准一定是针对 App 线下的性能表现来制定的。比如,你的 App 在线下连续 3 秒 CPU 占比都是在 70% 以下,那么 CPU 占比的监控值就可以设置为 3 秒内占比在 70% 以下。如果超过这个阈值就属于突发情况,就做报警处理,进行问题跟踪排查,然后有针对性地修复问题。
关于 WatchDog
WatchDog 是苹果公司设计的一种机制,主要是为了避免 App 界面无响应造成用户无法操作,而强杀掉 App 进程。造成 App 界面无响应的原因种类太多,于是苹果公司采用了一刀切的做法:凡是主线程卡死一定的时间就会被 WatchDog 机制强杀掉。这个卡死时间,WatchDog 在启动时设置的是 20 秒,前台时设置的是 10 秒,后台时设置的是 10 分钟。
由于 WatchDog 强杀日志属于系统日志,所以你的 App 上线后需要自己来监控卡顿,这样才能够在 WatchDog 强杀之前捕获到 App 卡死的情况。关于这部分内容的详细讲解,你可以参看苹果公司关于崩溃分析的文档。
关于 iOS 崩溃
关于实现崩溃问题自动定位到人,我认为通过堆栈信息来匹配到人是没有问题的。关于实现方法的问题,也就是第一个问题,你可以先做个映射表,每个类都能够对应到一个负责人,当获取到崩溃堆栈信息时,根据映射表就能够快速定位到人了。
对于第二个问题关于日志的收集方法,我想说的是 PLCrashReporter 就是用 handleSignalException 方法来收集的。
第三个关于 dSYM 解析堆栈信息工作原理的问题,也不是很复杂。dSYM 会根据线程中方法调用栈的指针,去符号表里找到这些指针所对应的符号信息进行解析,解析完之后就能够展示出可读的方法调用栈。
接下来,我来和你说说通过堆栈匹配到人的具体实现的问题。
第一步,通过 task_threads 获取当前所有的线程,遍历所有线程,通过 thread_info 获取各个线程的详细信息。
第二步,遍历线程,每个线程都通过 thread_get_state 得到 machine context 里面函数调用栈的指针。
thread_get_state 获取函数调用栈指针的具体实现代码如下:
获取到的这些函数调用栈,需要一个栈结构体来保存。
第三步,创建栈结构体。创建后通过栈基地址指针获取到当前栈帧地址,然后往前查找函数调用帧地址,并将它们保存到创建的栈结构体中。具体代码如下:
第四步,根据获取到的栈帧地址,找到对应的 image 的游标,从而能够获取 image 的更多信息。代码如下:
第五步,在知道了是哪个 image 后,根据 Mach-O 文件的结构,要想获取符号表所在的 segment,需要先找到 Mach-O 里对应的 Header。通过 _dyld_get_image_header 方法,我们可以找到 mach_header 结构体。然后,使用 _dyld_get_image_vmaddr_slide 方法,我们就能够获取虚拟内存地址 slide 的数量。而动态链接器就是通过添加 slide 数量到 image 基地址,以实现将 image 映射到未占用地址的进程虚拟地址空间来加载 image 的。具体实现代码如下:
第六步,计算 ASLR(地址空间布局随机化) 偏移量。
通过 ASLR 偏移量可以获取 segment 的基地址,segment 定义 Mach-O 文件中的字节范围以及动态链接器加载应用程序时这些字节映射到虚拟内存中的地址和内存保护属性。 所以,segment 总是虚拟内存页对齐。
第七步,遍历所有 segment,查找目标地址在哪个 segment 里。
除了 __TEXT segment 和 __DATA segment 外,还有 __LINKEDIT segment。__LINKEDIT segment 里包含了动态链接器使用的原始数据,比如符号、字符串、重定位表项。LC_SYMTAB 描述的是,__LINKEDIT segment 里查找的字符串在符号表的位置。有了符号表里字符串的位置,就能找到目标地址对应的字符串,从而完成函数调用栈地址的符号化。
这个过程的详细实现代码如下:
总结
在今天这篇文章中,我针对一些比较有代表性、你大概率会遇到的留言问题做了解答。这其中,包括第三方库的选择、性能衡量标准,以及崩溃分析方面的问题。
最后,对于第三方库的使用,我的建议是:如果和业务强相关,比如埋点或者 A/B 测试这样的库,最好是自建,你可以借鉴开源库的思路;一些基础的、通用性强的库,比如网络库和持续化存储的库,直接使用成熟的第三方库,既可以节省开发和维护时间,还能够提高产品质量;还有种情况就是,如果你所在团队较小,只有几个 iOS 开发人员,那么还是要尽可能地使用开源项目,你可以在 Awesome iOS上去找到适合团队的项目。
感谢你的收听,欢迎你在评论区给我留言分享你的观点,也欢迎把它分享给更多的朋友一起阅读。
分享给需要的人,Ta购买本课程,你将得18元
生成海报并分享
赞 0
提建议
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
上一篇
31 | iOS 开发学习资料和书单推荐
下一篇
33 | iOS 系统内核 XNU:App 如何加载?
精选留言(5)
- Connorlu2019-06-30我认为Firebase 的 A/B Testing 算是做的不错的一个第三方SDK。之所以说它不错,是因为它整合了数据上报,数据分析,PUSH消息和AI 预测等Firebase的其他功能。实现 A/B Testing能力是非常简单的事情,主要是如何较低成本的实现对 A/B Testing 的效果的数据统计和数据结论的展现,而Firebase在这一点上做的比较好。5
- 鼠辈2019-05-23学习了1
- Geek_cc73f22019-05-23老师好,我想问一下oom造成的crash能抓到吗,会不会那个时候没有内存空间让数据采集了呢?感谢
作者回复: oom 系统会去抓,系统回留内存去采集。你要在 App 内抓的话,需要在临近 oom 之前去抓。
1 - 提盏星灯逛人间2019-07-15- -像我们这种只有1个半的。。真的是能用开源就用开源
- 淡2019-05-23原生与前端共舞什么时候开讲啊
作者回复: 六月