性能优化终极生存指南
文章内容整理自 Session 《Ultimate application performance survival guide》,可观看视频获取第一用户体验。
其实刚看到题目时,很好奇的,生存指南?而且还是终极生存指南。这是户外生存挑战么?
我们都知道应用程序性能的重要性,不管是端侧,还是服务侧,高性能都是开发者们孜孜追求的目标。对于端侧来说,由于直接面向终端用户,所以用户体验的好坏直接影响到用户是否选择继续使用你的产品,或者是否会经常打开你的应用。而应用程序的性能直接影响到用户体验。
性能优化是一项长期而艰巨的任务,需要通过工具来跟踪许多指标。而这个 Seesion 就是为我们介绍了 Xcode 提供的五个主要工具,以帮助我们快速掌握这些工具以及一些固定的范式,从而提升我们应用的性能。这五个工具是
Xcode Organizer
MetricKit
Instruments
XCTest
App Store Connect API
Session 以性能指标开始,逐步展开每个指标中一些常见的问题及解决和预防的方法。
性能指标
对于应用程序而言,衡量其性能主要有 8 个关键指标:电池使用情况、启动时间、挂起率、内存、磁盘写入、滚动、终止和 MXSignposts。
每个指标的衡量都有特定的范式和通用的工具集,下面一个一个来看。
电池使用
一个应用是否耗电,决定了用户是否要经常打开这这个应用。毕竟,如果应用的耗电量过大,用户在打开前就会有顾虑。iPhone 本身电池容量相比其它产商就小,也不是所有人都会带个充电宝出门的。
我们可以在 iPhone 的设置的电池展示页看到每个应用的具体耗电情况。通过优化电池寿命,用户可以更长时间地使用设备和应用。影响电池寿命有因素有很多,不过需要重点关注三个方面:
CPU
网络
位置
我们可以通过 Xcode 的 Energy Gauge 来跟踪 CPU 的使用情况。
在 Debug 导航器中找到 Energy Gauge,这个面板中有两个区域:
高 CPU 利用率:CPU 使用率大于 20%,以下情况会导致高 CPU 利用率
绘制用户界面
处理网络数据
执行计算
CPU 唤醒开销:CPU 从空闲状态唤醒的区域,会有一定的消耗
可以通过以下工具到定位问题
Instruments
单击面板右下角的 Time Profile进入,可以查看查看热状态、CPU 使用情况和 profile 过程中的活动调用堆栈
位置能量模型
衡量 Core Location 的影响,并确保应用程序在不应该使用的位置时不使用该位置
MatricKit
一个性能测试框架
在需要更多日志记录和上下文来调试时,可以使用这个框架
要使用 MatricKit,只需要在应用中自定义一个类,并实现 MXMetricManagerSubscriber 协议,并实现几个固定的方法
借助苹果的分析管道,就可以获取到数据的简单版本。
当用户同意分享性能数据后,数据会在苹果的服务器上汇总,并通过诸如 Xcode Organizer 等工具反馈给开发者。之后,我们只需要打开 Organizer,就可以看到应用各个版本的数据汇总。
通过不同的视图,我们可以查看不同的信息,如 CPU 使用率高的区域、网络流量等等。
另外,还可以通过 App Store Connect API 来获取所有这些数据,数据会以 JSON 格式返回。
Hang Rate 和滑动
挂起是指应用对用户输入或操作至少 250 毫秒没有响应。应用程序中的挂起可能会导致用户从应用程序切换器强杀程序,并且是用户在应用程序中体验的主要障碍,应优先考虑。
而在滑动列表的过程中,则可能会出现卡顿问题,这会大大影响用户的使用体验,这也是社区讨论的一大重点,已有不少高质量的文章来描述如丝般顺滑的滑动体验。
我们可以在 Organizer 中查看挂起和滑动的指标数据。如果图表有上升趋势
或者在滑动过程中,出现黄色或红色色条,则表明存在问题,需要优化。
我们可以使用 Instruments 通过使用线程状态或系统调用跟踪来检测挂起的原因。线程状态跟踪工具显示线程状态的时间线以及操作系统安排线程运行的时间。在详细信息部分看到一个线程被阻塞了多长时间。
可以使用 XCTest 编写一个性能测试来启动和滑动应用。在测试中,指定要测量 scrollDeceleration submetric,并且在代码块的主体中,以应用程序中期望的滚动速度向上滑动。
另外,同样借助 MetricKit,可以从用户那里获取到诊断信息。在出现滑动卡顿时,iOS 15 在 MetricKit 中引入了一个新的 API 来使用 MXSignpost 标记自定义动画。
MXSignpost 是 MetricKit 附带的包装器 API,它允许标记遥测的关键代码部分。使用 MXSignpostAnimation-IntervalBegin API,将能够标记自定义动画的开始。使用 MXSignpost 结束 API,可以标记动画的结束并在该时间间隔内收集故障率遥测数据。这两个函数不仅会捕获此间隔的粒度性能数据,还会捕获发生的任何故障。
磁盘
写入磁盘可能会磨损用户的 NAND,导致设备运行状况不佳。写入也需要花费大量时间,如果频繁执行,可能会导致糟糕的用户体验和性能下降,因此对这些写入进行批处理非常重要。
使用 Instruments 中的文件活动模板来分析应用程序。这会以系统调用的形式记录文件系统的使用情况,因此可以轻松识别应用程序代码中访问文件系统的位置。
有很多方法来限制写入磁盘。常见的是批量写入操作,使用 Core Data 处理频繁更改的数据,以及避免快速创建和删除文件。
还可以使用 XCTest 编写性能测试来测量应用程序的磁盘使用情况,以防止具有过多磁盘写入的代码在用户设备上运行。
如果已经发布了具有高磁盘写入的应用程序版本,可以使用管理器来跟踪其在用户设备上的性能。
Disk Writes 指标向展示了与之前发布的版本相比,应用程序的当前版本正在执行的写入次数的趋势。图中的尖峰表示应用程序存在导致大量写入的错误。应该找出这些写作的主要来源,理解它们,并寻找减少它们的方法。
在 Xcode 13 中,还可以获得名为 Insights 的其他详细信息, 这指明了一些简单的优化,可以通过这些优化减少应用程序中的一些写入。
使用 MetricKit 来监控应用程序的磁盘使用情况,可以使用 MXSignpost 间隔对关键的磁盘写入路径进行预估,以收集更细粒度的遥测数据,这可以帮助发现优化的机会。
启动时间和终止
启动时间优化也是一个热门话题。启动时间是用户点击应用程序图标和应用程序中呈现第一帧之间的时间量。如果用户花很长时间等待应用程序启动,显然会很影响用户体验。同时可能会导致系统终止应用程序。当系统终止应用程序后,用户将从一开始就体验整个启动流程,这比从后台运行状态恢复花费的时间要长得多。
进程退出的原因有很多,例如达到并超过系统内存限制或启动超时。
进入 Organizer 中,可以查看 启动时间 和 新的 终止 项。查看启动时间可以了解应用程序在过去 16 个版本中的平均“第一帧时间”是多少,因此可以看到添加新功能之前的速度有多快。
在 “终止” 窗格中查看应用程序因启动需要多长时间而被系统终止的频率。
通过使用 Instruments 中的 App Launch 模板来分析应用程序的启动时间来测试这个问题。这个模板运行应用程序五秒钟,在此期间它收集时间配置文件和应用程序启动时发生的事情的线程状态跟踪,所以可以找出线程被阻塞的原因并修复它。
当然,同样可以通过 XCTest 和 MetricKit 来分析。
内存
我们都知道应用程序使用的内存走过限制时,会被系统终止。我们可以在 Organizer 中查看内存指标。
可以使用 Instruments 中的 Leaks、Allocations 和 VM Tracker 模板来分析应用程序的内存使用情况。Leaks将检查进程的堆并检查泄漏的内存。Allocations将分析应用程序的内存生命周期。VM Tracker 会随着时间的推移显示应用程序的虚拟内存空间。
还可以使用 MetricKit 来获取相同的信息并对其运行自己的分析。
小结
性能优化是一个永恒的主题。会有很多问题,也会有很多解决方案。在这方面,Xcode 提供的工具也很多,我们可以通过组合这些工具来分析定位问题,并具体问题具体分析解决。
-End-
最近有一些小伙伴,让我帮忙找一些 面试题 资料,于是我翻遍了收藏的 5T 资料后,汇总整理出来,可以说是程序员面试必备!所有资料都整理到网盘了,欢迎下载!
面试题
】即可获取