MetricKit框架详细解析(七) —— Reducing Y
版本记录
版本号 | 时间 |
---|---|
V1.0 | 2021.05.14 星期五 |
前言
MetricKit
由iOS13系统进引入,用来汇总和分析有关异常和崩溃诊断以及电源和性能指标的每个设备的报告。下面我们就一起来看下这个框架。感兴趣的可以看下面几篇文章。
1. MetricKit框架详细解析(一) —— 基本概览(一)
2. MetricKit框架详细解析(二) —— Improving Your App's Performance(一)
3. MetricKit框架详细解析(三) —— Reducing Your App's Memory Use(一)
4. MetricKit框架详细解析(四) —— Gathering Information About Memory Use(一)
5. MetricKit框架详细解析(五) —— Making Changes to Reduce Memory Use(一)
6. MetricKit框架详细解析(六) —— Preventing Memory-Use Regressions & Responding to Low-Memory Warnings(一)
Overview
通过最大程度地减少启动时间,为您的应用程序创建更快响应的体验。
用户首次使用应用程序时会等待其启动。启动屏幕向用户显示该应用程序正在准备使用,但也应准备就绪,可以帮助用户尽快完成任务。启动时间太长的应用可能会使用户感到沮丧,并且如果响应时间太长,iOS看门狗进程甚至可能终止它。如果应用是常规工作流程的一部分,则用户一天可能会启动多次该应用,而且启动时间过长会导致用户等待执行任务的时间有所延迟。
当用户在主屏幕上点击某个应用程序的图标时,iOS会在将控制权移交给该应用程序流程之前为该应用程序做好启动准备。然后,该应用程序运行代码以准备将其UI绘制到屏幕上。即使在显示应用程序的用户界面之后,该应用程序仍可能仍在准备内容或用最终控件替换插页式界面(例如,加载微调器)。这些步骤中的每一个都会影响应用程序的总启动时间,您可以采取一些步骤来缩短其持续时间。
Gather Metrics About Your App’s Launch Time
在Launch Time pane
中或使用MetricKit
查看应用程序的启动时间指标。
使用Xcode中的Launch Time pane
可查看用户点击图标以启动应用程序到系统绘制启动屏幕以外的时间之间的毫秒数。 使用过滤器检查不同设备上的启动时间,以及典型时间(第50个百分位数)和最长时间(第90个百分位数)。 通过单击图表中所需的release
版上的栏,将当前release
版的发布时间与先前release
版的发布时间进行比较。
除了启动时间外,MetricKit
还报告恢复应用程序的时间。
Profile Your App's Launch Time
使用App Launch template
在Instruments
中为您的应用进行调试。 Instruments
会在您的应用程序运行五秒钟,在此期间,它会收集时间配置文件(time profile)
和线程状态跟踪。 使用时间配置文件来识别您的应用在启动过程中正在运行的代码。 使用线程状态跟踪来查找线程活动或被阻塞的时间,并发现线程被阻塞的原因。
剖析应用在不同情况下的启动时间,以了解这些因素如何影响体验。 以下是一些要测试的不同情况的示例:
- 打开设备,首次解锁,然后启动您的应用程序。
- 强制退出您的应用程序,然后启动它。
- 打开其他应用程序,然后启动您的应用程序。
- 使用非常大的应用程序(例如,可以使用许多图形资源或实时摄像机输入的应用程序),然后启动您的应用程序。
UIKit在主线程上绘制视图并处理用户事件,因此在应用程序启动完成后,该线程必须可用于绘制第一帧。 在Instruments
线程跟踪中,主线程花费在运行或抢占上的时间是其无法绘制视图或响应用户输入事件的时间。
对于不同的应用启动视图,请使用Time Profile template
板对应用进行分析。 App Life Cycle
时间轴将应用程序启动期间的活动分为process initialization, UIKit initialization, UIKit initial scene rendering
和 initial frame rendering
。
Identify Launch-Time Factors: Dynamic Library Loading
dynamic loader (dyld)
加载应用程序的可执行文件,并检查可执行文件中的Mach
加载命令,以查找应用程序所需的框架和动态库。 然后,它将每个框架加载到内存中,并解析可执行文件中的动态符号,以指向动态库中的适当地址。
应用程序加载的每个其他框架都会增加启动时间。 尽管dyld
在用户安装应用程序时将大量此类工作缓存在启动闭包中,但是启动闭包的大小以及加载后的工作量仍取决于所加载库的数量和大小。 您可以通过限制嵌入的框架数量来减少应用程序的启动时间。 您在Xcode的Target editor
中导入或添加到应用的“Linked Frameworks and Libraries”
设置中的框架将计入该数字。
Identify Launch-Time Factors: Static Initializers
应用程序中的某些代码必须在iOS运行应用程序的main()
函数之前运行,这会增加启动时间。 该代码包括:
-
C ++
静态构造函数。 - 在类或类别中定义的
Objective-C +load
方法。 - 标有
clang attribute __attribute__((constructor))
的函数。 - 链接到应用程序或框架二进制文件的
__DATA
,__ mod_init_func
区的任何函数。
在可能的情况下,将代码移至应用程序生命周期的后期,即应用程序启动完成后但需要工作结果之前。 在Instruments
中,Static Initializer Calls
工具测量您的应用程序花费在运行静态初始化程序上的时间。
Identify Launch-Time Factors: UIKit Lifecycle Methods
UIKit
初始化您的应用程序代理类(符合UIApplicationDelegate
协议的类)的实例,并将其发送给application:willFinishLaunchingWithOptions:
和application:didFinishLaunchingWithOptions:
消息。 UIKit
在主线程上发送这些消息,而用这些方法执行代码所花费的时间增加了应用程序的启动时间。使用这些方法仅做准备应用程序初始显示所需的工作;将其他任务推迟到应用程序生命周期中的更合适的时间。
如果在刷新内容时向用户显示陈旧的内容有意义,则将数据模型与网络服务的同步推迟到应用程序运行为止。将同步移到异步后台队列。注册后台任务以从网络服务获取更新,以减少启动时数据的陈旧性和使数据保持最新状态所需的工作量。
在首次使用而不是在应用启动时初始化非视图功能,例如持久性存储和位置服务。仅检索显示应用的初始视图所需的数据。请注意您的应用程序是否正在还原状态,并准备显示正在还原的视图所需的数据。如果未还原任何状态,则仅准备默认的初始视图。例如,默认情况下,图库应用程序可能会显示图像缩略图的集合,并允许用户选择照片以获取详细视图。如果应用程序启动时没有恢复状态,则只需显示一个占位符即可显示一小屏缩略图,并在应用程序启动完成后用真实的图像缩略图填充它们。在用户点击缩略图之一之前,不需要加载完整的详细图像。
初始化已知在首次启动时可行的应用行为的受限子集。例如,任务管理器应用程序可以让用户在启动时创建新任务,即使该应用程序尚未从其持久性存储或网络服务中检索到用户的所有现有任务。
Identify Launch-Time Factors: Drawing Initial View Hierarchy
Xcode Organizer
和MetricKit
都使用第一帧的时间作为启动时间的度量,包括绘制在第一帧上显示的视图所需的时间。将视图添加到视图层次结构必须限于主线程,因此,具有更多视图的更复杂的视图层次结构比简单层次结构需要更长的渲染时间。
减少应用程序初始视图的复杂性可以缩短加载时间,用标准视图替换重载drawRect:
的自定义视图也可以达到缩短时间的效果。在需要自定义绘图的地方,请注意传递给draw(_ :)
的矩形,并且仅在该矩形内渲染视图的一部分。这样做可以避免对视图中未渲染到屏幕的部分进行图像解码和计算颜色,坐标和绘图命令。
Track Additional Startup Activities
启动时间度量标准衡量的是从用户点击其主屏幕上的应用程序图标到将应用程序的第一帧绘制到屏幕上的时间。绘制default.png
或启动屏幕storyboard
的过程在此期间进行,并且其外观不会结束启动时间计数器。
如果您的应用在绘制第一帧之后但在用户开始使用该应用之前仍需要运行代码,则该时间不会影响启动时间指标。额外的启动活动仍然有助于提高用户对应用程序响应能力的认识。
要跟踪其他启动活动,请在应用程序中创建类别为pointsOfInterest
的OSLog
对象。使用os_signpost
函数记录应用程序准备任务的开始和结束,如以下示例所示:
class ViewController: UIViewController {
static let startupActivities:StaticString = "Startup Activities"
let poiLog = OSLog(subsystem: "com.example.CocoaPictures", category: .pointsOfInterest)
override func viewDidLoad() {
super.viewDidLoad()
os_signpost(.begin, log: self.poiLog, name: ViewController.startupActivities)
// do work to prepare the view
os_signpost(.end, log: self.poiLog, name: ViewController.startupActivities)
}
在Instruments
中,Points of Interest
在其时间轴中显示signposts
。 您可以使用此信息将应用程序中的活动与应用程序的其他启动任务相关联。
后记
本篇主要讲述了
Reducing Your App's Launch Time
,感兴趣的给个赞或者关注~~~