精确计算应用的冷启动耗时

在iOS项目中,冷启动时间是指从用户点击应用图标开始,到应用完全加载并呈现出第一个界面(可能需要网络请求必要的数据)所花费的时间。这里以 main 函数为界,分为两个时间段:

  • 从用户点击应用图标 ~ invoke main func
  • invoke main func ~ 首屏渲染完成

计算 main 函数调用之前的耗时

通过添加环境变量 DYLD_PRINT_STATISTICS,可以准确计算应用程序的 Pre-main Time(即在 main 函数之前的启动时间)。DYLD_PRINT_STATISTICS 环境变量由动态链接器 dyld 提供,用于输出启动过程中各种操作的时间统计信息。

使用 DYLD_PRINT_STATISTICS 计算 Pre-main Time

  1. 打开 Xcode 并选择你的项目
  2. 选择项目的 Scheme,点击 Edit Scheme…
  3. 在左侧选择 Run 选项卡,然后选择 Arguments 子选项卡。
  4. Environment Variables 部分,点击 + 按钮添加新的环境变量:
    • Name: DYLD_PRINT_STATISTICS
    • Value: 1
  5. 点击 Close 保存更改。

运行应用并查看输出

  1. 运行你的应用程序。在 Xcode 的调试控制台中,你会看到 dyld 输出的详细启动时间统计信息,包括以下几个部分:
    • Total pre-main time:从启动应用程序到调用 main 函数之间的总时间。
    • dylib loading time:加载动态库所花费的时间。
    • rebase/binding time:重定位和绑定符号的时间。
    • ObjC setup time:Objective-C 运行时环境的初始化时间。
    • initializer time:执行全局和静态变量的初始化时间。

解析输出示例

以下是调试控制台中可能看到的输出示例:

Total pre-main time: 200.21 milliseconds (100.0%)dylib loading time:  50.03 milliseconds (25.0%)rebase/binding time:  30.01 milliseconds (15.0%)ObjC setup time:  20.05 milliseconds (10.0%)initializer time: 100.12 milliseconds (50.0%)

解释输出

  • Total pre-main time:总的 Pre-main 时间,从应用程序启动到 main 函数开始执行的时间。这包括动态库加载、重定位和符号绑定、Objective-C 运行时初始化、以及全局和静态变量的初始化时间。
  • dylib loading time:加载动态库(dylibs)所花费的时间。
  • rebase/binding time:重定位(rebase)和符号绑定(binding)所花费的时间。
  • ObjC setup time:初始化 Objective-C 运行时环境所花费的时间。
  • initializer time:执行全局和静态变量初始化所花费的时间。

通过这些数据,可以了解应用启动过程中各个阶段的时间消耗,特别是 Pre-main 时间,这对于优化应用的启动性能非常有帮助。

优化建议

根据 Pre-main 时间的统计信息,可以针对性地进行优化,例如:

  1. 减少动态库数量:减少应用程序依赖的动态库数量,可以显著减少动态库加载时间。
  2. 优化符号绑定:通过减少符号绑定和重定位的数量,可以降低 rebase/binding 时间。
  3. 优化全局变量初始化:避免复杂和耗时的全局变量初始化,尽量推迟到实际使用时再初始化。
  4. 减少 Objective-C 类的数量:减少 Objective-C 类的数量和复杂性,可以降低 ObjC setup 时间。

通过这些优化措施,可以有效减少 Pre-main 时间,从而提升应用的启动速度。

小结

通过添加环境变量 DYLD_PRINT_STATISTICS,可以准确计算和分析应用的 Pre-main 时间。这为优化应用的启动性能提供了详细的参考数据,使开发者能够更有针对性地进行优化。


计算 main 函数到首屏渲染完成的耗时

main 函数到完全呈现出第一个界面的时间,特别是在第一个界面涉及网络请求的情况下,计算这一段时间可以通过以下几步来实现:

方法 1:使用 os_signpost API 记录时间

在应用的关键点添加 os_signpost 标记,并结合 Instruments 工具进行分析。

步骤 1:设置 os_signpost 标记

main 函数中和第一个界面呈现完成后添加 os_signpost 标记。

import os.signpostlet log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Performance")@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {var window: UIWindow?var signpostID = OSSignpostID(log: log)static func main() {os_signpost(.begin, log: log, name: "App Launch", signpostID: OSSignpostID(log: log))UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(AppDelegate.self))}func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {// 初始化代码...return true}
}class YourViewController: UIViewController {override func viewDidAppear(_ animated: Bool) {super.viewDidAppear(animated)// 假设这是进行网络请求并更新界面的方法fetchDataAndUpdateUI()}func fetchDataAndUpdateUI() {// 开始网络请求let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "Performance")let signpostID = OSSignpostID(log: log)os_signpost(.begin, log: log, name: "Fetch Data", signpostID: signpostID)// 模拟网络请求DispatchQueue.global().async {sleep(2) // 模拟网络延迟DispatchQueue.main.async {// 完成网络请求并更新UIos_signpost(.end, log: log, name: "Fetch Data", signpostID: signpostID)os_signpost(.end, log: log, name: "App Launch", signpostID: OSSignpostID(log: log))// 更新UI代码...}}}
}
步骤 2:使用 Instruments 工具进行分析
  1. 打开 Xcode 并选择你的项目
  2. 选择 Product > Profile 或使用快捷键 Command + I 启动 Instruments。
  3. 在 Instruments 中选择 Signpost Instrument 模板并点击 Choose
  4. 在 Instruments 界面中,点击 Record 按钮,启动你的应用。
  5. 在左侧的活动记录(Activity Trace)中,可以看到 App LaunchFetch Data 的开始和结束时间。

通过这种方法,可以准确地测量从 main 函数开始到第一个界面完全呈现出来的时间,包括网络请求所花费的时间。

方法 2:手动记录时间戳

在关键点手动记录时间戳,并计算总耗时。

步骤 1:记录时间戳

AppDelegate 和视图控制器中记录时间戳。

import UIKit@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {var window: UIWindow?static var launchStartTime: TimeInterval?static var firstViewControllerLoadTime: TimeInterval?static func main() {launchStartTime = Date().timeIntervalSince1970UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(AppDelegate.self))}func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {// 初始化代码...return true}
}class YourViewController: UIViewController {override func viewDidAppear(_ animated: Bool) {super.viewDidAppear(animated)// 假设这是进行网络请求并更新界面的方法fetchDataAndUpdateUI()}func fetchDataAndUpdateUI() {// 开始网络请求let startTime = Date().timeIntervalSince1970// 模拟网络请求DispatchQueue.global().async {sleep(2) // 模拟网络延迟DispatchQueue.main.async {// 完成网络请求并更新UIlet endTime = Date().timeIntervalSince1970if let launchStartTime = AppDelegate.launchStartTime {let totalLaunchTime = endTime - launchStartTimeprint("Total launch time including network request: \(totalLaunchTime) seconds")}// 更新UI代码...}}}
}
步骤 2:运行并查看输出
  1. 运行你的应用程序
  2. 在调试控制台中查看总的启动时间,包括网络请求的时间。

小结

通过上述方法,可以准确计算从 main 函数到第一个界面完全呈现出来的时间,尤其是在涉及网络请求的情况下。使用 os_signpost API 结合 Instruments 工具进行分析,可以提供更详细和精确的性能测量数据。而手动记录时间戳的方法则相对简单,但同样能提供一个大致的时间估计。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/40096.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(4)深入探索与优雅安装:Pandas数据处理的魅力之旅

目录 1. 前言1.1 Pandas 概述1.2 Pandas 特点1.3 优化应用举例1.4 Pandas 应用场景 2. DataFrame2.1 DataFrame结构2.2 Pandas 安装2.2.1 Pandas 安装准备2.2.2 Pandas 安装2.2.3 Pandas 包的导入2.2.4 查看 pandas 版本2.2.5 一个简单的 1. 前言 1.1 Pandas 概述 pandas 是 …

大数据招商的应用场景及实施路径有哪些?

当下,我国已经进入数字经济与实体经济融合发展的新阶段,数字技术和数字化转型落地日臻成熟,数据要素价值释放深入到了我国各个领域的发展,招商引资也不例外,在传统招商模式效果日渐甚微的大环境下,大数据招…

Java 基础知识之 switch 语句和 yield 关键字

传统 switch 语句 传统的 switch 语句我们已经写了一万遍了,以下是一个典型的 switch 语句: int dayOfWeek 3; switch (dayOfWeek) {case 1:System.out.println("星期一");break;case 2:System.out.println("星期二");break;case…

NAT地址转换实验,实验超简单

实验拓扑 实验目的 将内网区域&#xff08;灰色区域&#xff09;的地址转换为172.16.1.0 实验过程 配置静态NAT&#xff08;基于接口的静态NAT&#xff09; R1配置 <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]sysname R1 [R1]un in en I…

游戏AI的创造思路-技术基础-自然语言处理

自然语言处理-可以对游戏AI特别是RPG类、语言类游戏进行“附魔”&#xff0c;开发出“随机应变”和你聊天的“女友”、“队友”或者是根据你定义的文本库来用接近自然语言的生成“语言”&#xff0c;推动游戏情景在受控范围内前进 目录 1. 自然语言处理定义 2. 发展历史 3. …

泛微开发修炼之旅--26前端j实现手机号码验证

文章链接&#xff1a;26前端j实现手机号码验证

AiPPT的成功之路:PMF付费率与增长策略

如果要给 2023 年的 AI 市场一个关键词&#xff0c;那肯定是“大模型”&#xff0c;聚光灯和大家的注意力、资金都投向了那些大模型公司&#xff1b;而如果要给 2024 年的 AI 市场一个关键词&#xff0c;则一定是 PMF&#xff08;产品市场契合&#xff09;。如果没有 PMF&#…

五粮液:稳,还稳得住吗?

前有“酱香”茅台一骑绝尘&#xff0c;后有“清香”汾酒21%的增速虎视眈眈。 在新的股东大会上&#xff0c;管理层把“稳”字说了近30次。 就问白酒二哥——五粮液&#xff0c;你还稳得住吗&#xff1f; 近期&#xff0c;白酒大哥茅台因跌价吸引各方关注&#xff0c;但在这一…

人脸重建迁移攻击FRTA:绕过各种未见过的面部识别系统

随着人脸识别系统在安全关键环境中的部署日益增多&#xff0c;威胁行为者正在开发针对各种攻击点的复杂攻击策略。在这些攻击策略中&#xff0c;面部重建攻击是一个主要的威胁。面部重建攻击的主要目的是创建伪造的生物特征图像&#xff0c;这些图像类似于存储的生物特征模板中…

头条系统-05-延迟队列精准发布文章-概述添加任务(db和redis实现延迟任务)、取消拉取任务定时刷新(redis管道、分布式锁setNx)...

文章目录 延迟任务精准发布文章 1)文章定时发布2)延迟任务概述 2.1)什么是延迟任务2.2)技术对比 2.2.1)DelayQueue2.2.2)RabbitMQ实现延迟任务2.2.3)redis实现 3)redis实现延迟任务4)延迟任务服务实现 4.1)搭建heima-leadnews-schedule模块4.2)数据库准备4.3)安装redis4.4)项目…

【系统架构设计师】计算机组成与体系结构 ⑨ ( 磁盘管理 | “ 磁盘 “ 单缓冲区 与 双缓冲区 | “ 磁盘 “ 单缓冲区 与 双缓冲区案例 )

文章目录 一、" 磁盘 " 单缓冲区 与 双缓冲区1、" 磁盘 " 单缓冲区2、" 磁盘 " 双缓冲区 二、" 磁盘 " 单缓冲区 与 双缓冲区案例1、案例描述2、磁盘单缓冲区 - 流水线分析3、磁盘双缓冲区 - 流水线分析 一、" 磁盘 " 单缓冲…

2024年电子信息工程与电气国际学术会议 (EIEEE 2024)

2024年电子信息工程与电气国际学术会议 &#xff08;EIEEE 2024&#xff09; 2024 International Academic Conference on Electronic Information Engineering and Electrical Engineering 【重要信息】 大会地点&#xff1a;北京 大会官网&#xff1a;http://www.iceieee.co…

Unity休闲手机游戏开发课程

课程介绍 Unity休闲手机游戏开发课程将教您如何利用Unity游戏引擎创建令人愉快的休闲手机游戏。从基础的游戏开发知识到高级的游戏制作技巧&#xff0c;您将学习到创建各种类型的休闲游戏所需的关键技能和工具。无论您是初学者还是有一定经验的开发者&#xff0c;本课程都能帮助…

【Linux】TCP协议【下三】{面向字节流/粘包问题/TCP异常情况/文件和Socket}

文章目录 7.面向字节流TCP&#xff08;传输控制协议&#xff09;和UDP&#xff08;用户数据报协议&#xff09; 8.粘包问题9.TCP异常情况10.再谈文件和socket的关系 7.面向字节流 创建一个TCP的socket, 同时在内核中创建一个 发送缓冲区 和一个 接收缓冲区;一个链接一对发收缓…

使用Charles实现Android抓包,附带Charles破解教程

1.下载Charles 网址&#xff1a;下载Charles 安装完成后的界面&#xff1a; 2.配置http抓包 点击该选项 可以看到代理的 ip 和端口号 然后在手机的wifi中配置代理&#xff08;手机和电脑要在同一局域网&#xff09;&#xff0c;代理选择手动&#xff0c;并填入ip和端…

大语言模型测评工具-ChatHub和ChatAll

背景 现在国内外拥有上百个大语言模型&#xff0c;在AI业务中&#xff0c;我们需要在其中选择一个合适业务模型&#xff0c;就需要对这些模型进行测试。手工去测试这么多模型效率一定不高&#xff0c;今天就介绍两个提高测评模型效率的工具 ChatHub和ChatAll。 介绍 ChatHub…

钉钉在MAKE 2024大会上宣布开放AI生态;NBC将用AI主播播报巴黎奥运会内容

&#x1f680; 钉钉在MAKE 2024大会上宣布开放AI生态 摘要&#xff1a;钉钉总裁叶军在MAKE 2024生态大会上宣布&#xff0c;钉钉将对所有大模型厂商开放&#xff0c;构建“国内最开放AI生态”。目前已有六家大模型厂商接入钉钉&#xff0c;用户可直接使用七家大模型产品。未来…

UnityUGUI之三 Text

富文本 常用语法&#xff1a; 1.加粗 <b> text </b> 2.斜体 <i> text </i> 3.尺寸 <size?> text </size> 4.颜色 <color#ff0000> text </color>

UE5 02-给物体一个扭矩力

需要注意的是: 1.弹簧臂 可以使用绝对旋转 这样就可以不跟随父物体Player的旋转 2.弹簧臂 进行碰撞测试勾选,当这个弹簧线被遮挡,摄像机会切换到碰撞点位置 进行碰撞测试勾选,当这个弹簧线被遮挡,摄像机不会切换到碰撞点位置

【TypeScript】TS入门到实战(详解:高级类型)

目录 第三章、TypeScript的数据类型 3.1 TypeScript的高级类型 3.1.1 class 3.1.1.1 熟悉class类 3.1.1.2 class类继承的两种方式 3.1.1.3 class类的5种修饰符 3.1.2 类型兼容 3.1.3 交叉类型 3.1.4 泛型 3.1.4.1 创建泛型函数 3.1.4.2 泛型函数的调用 3.1.4.3 泛型…