如何优化 App 的启动耗时?

原文:iOS面试题大全

iOS 的 App 启动主要分为以下步骤:

  • 打开 App,系统内核进行初始化跳转到 dyld 执行。这个过程包括这些步骤:1)分配虚拟内存空间;2)fork 进程;3)加载 MachO (自身所有的可执行 MachO 文件的集合)到进程空间;4)加载动态链接器 dyld 并将控制权交给 dyld 处理。在这个过程中内核会产生 ASLR(Address space layout randomization) 随机数值,这个值用于加载的 MachO 起始地址在内存中的偏移,随机的地址可防止 MachO 代码扫描并被 hack,提升安全性。通过 ASLR 虽然可随机化各内存区基地址,但无法将程序内的代码段和数据段随机化,如果绕过(bypass) ASLR 依然可进行篡改,就需要结合 PIE(Position Independent Executable) 共同使用。与之相似的还有 PIC(Position Independent Code),位置无关代码,作用于共享库代码。PIE/PIC 技术需要在编译阶段开启。顾名思义,PIC 可将程序代码装载到任意地址,这样就内部的指针不能靠固定的绝对地址访问,而通过相对地址指令如 adrp 来获取代码和数据。
  • 进入 dyld 动态链接器,它负责将一个 App 处理为一个可运行的状态,包含:
  • 加载 MachO 的依赖库(这些依赖库也是 MachO 格式的文件)。dyld 从可执行 MachO 文件的依赖开始, 递归加载所有依赖的动态库。 动态库包括:iOS 中用到的所有系统动态库:加载 OC runtime 方法的 libobjc,系统级别的 libSystem(例如 libdispatch(GCD) 和 libsystem_blocks(Block));其他 App 自己的动态库。根据 Apple 的描述,大部分 App 所加载的库在 100~400 个。不过 iOS 系统库已经被特殊优化过,如提前加入共享缓存,提前做好地址修正等。
  • Fix-ups(地址修正),包括 rebasing 和 binding 等。ASLR + PIE 技术增强了程序的安全性,使得依赖固定地址进行攻击的方法失效,但也增加了程序自身的复杂度,MachO 文件的 rebase 和 bind info 等部分以及启动时的 fix-ups 地址修正阶段就是配合它而产生的。
  • ObjC 环境配置。经过了 MachO 程序和依赖库的加载以及地址修正之后,dyld 所做的大部分事情已经完成了。在这一阶段,dyld 开始对主程序的依赖库进行初始化工作,而初始化的执行部分会回调到依赖库内部执行,如 ObjC 的运行时环境所在的 libobjc.A.dylib 以及 libdispatch.dylib 等。ObjC Setup 的过程,主要是对 ObjC 数据进行关联注册:1)dyld 将主程序 MachO 基址指针和包含的 ObjC 相关类信息传递到 libobjc;2)ObjC Runtime 从 __DATA 段中获取 ObjC 类信息,由于 ObjC 是动态语言,可以通过类名获取其实例,所以 Runtime 维护了一个映射所有类的全局类名表。当加载的数据包含了类的定义,类的名字就需要注册到全局表中;3)获取 protocol、category 等类相关属性并与对应类进行关联;4)ObjC 的调用都是基于 selector 的,所以需要对 selector 全局唯一性进行处理。以上步骤由 dyld 启动 libSystem.dylib 统一对基础库进行调用执行,这里面就包含了 libobjc 的 Runtime,同时 Runtime 会在 dyld 绑定回调,当 dyld 处理完相关数据后就会调用 ObjC Runtime 执行 Setup 工作。
  • 执行各模块初始化器。从这一步就开始接近上(业务)层:1)通过 ObjC Runtime 在 dyld 注册的通知,当 MachO 镜像准备完毕后,dyld 会回调到 ObjC 中执行 +load() 方法,包括以下步骤:a)获取所有 non-lazy class 列表;b)按继承以及 category 的顺序将类排入待加载列表;c)对待加载列表中的类进行方法判断并调用 +load() 方法。2)执行 C/C++ 初始化构造器,如通过 attribute((constructor)) 注解的函数。3)如果包含 C++,则 dyld 同样会回调到 libc++ 库中对全局静态变量、隐式初始化等进行调用。
  • 查找并跳转到 main() 函数入口。到了最后,dyld 回到 Load command,找到 LC_MAIN,拿到 entryoff 再加上 MachO 在内存的加载首地址(首地址就是内核传来的 slide 偏移)就得到了 main() 的入口地址,从而进入我们显式的程序逻辑。

进入 main() -> UIApplicationMain -> 初始化回调 -> 显示UI。

iOS 的 App 启动时长大概可以这样计算:

t(App 总启动时间) = t1(main 调用之前的加载时间) + t2(main 调用之后的加载时间)。

t1 = 系统 dylib(动态链接库)和自身 App 可执行文件的加载。

t2 = main 方法执行之后到 AppDelegate 类中的 application:didFinishLaunchingWithOptions:方法执行结束前这段时间,主要是构建第一个界面,并完成渲染展示。

在 t1 阶段加快 App 启动的建议:

  • 尽量使用静态库,减少动态库的使用,动态链接比较耗时。
  • 如果要用动态库,尽量将多个 dylib 动态库合并成一个。
  • 尽量避免对系统库使用 optional linking,如果 App 用到的系统库在你所有支持的系统版本上都有,就设置为 required,因为 optional 会有些额外的检查。
  • 减少 Objective-C Class、Selector、Category 的数量。可以合并或者删减一些 OC 类。
  • 删减一些无用的静态变量,删减没有被调用到或者已经废弃的方法。
  • 将不必须在 +load 中做的事情尽量挪到 +initialize 中,+initialize 是在第一次初始化这个类之前被调用,+load 在加载类的时候就被调用。尽量将 +load 里的代码延后调用。
  • 尽量不要用 C++ 虚函数,创建虚函数表有开销。
  • 不要使用 __atribute__((constructor)) 将方法显式标记为初始化器,而是让初始化方法调用时才执行。比如使用 dispatch_once()pthread_once() std::once()
  • 在初始化方法中不调用 dlopen()dlopen() 有性能和死锁的可能性。
  • 在初始化方法中不创建线程。

在 t2 阶段加快 App 启动的建议:

  • 尽量不要使用 xib/storyboard,而是用纯代码作为首页 UI。
  • 如果要用 xib/storyboard,不要在 xib/storyboard 中存放太多的视图。
  • application:didFinishLaunchingWithOptions: 里的任务尽量延迟加载或懒加载。
  • 不要在 NSUserDefaults 中存放太多的数据,NSUserDefaults 是一个 plist 文件,plist 文件被反序列化一次。
  • 避免在启动时打印过多的 log。
  • 少用 NSLog,因为每一次 NSLog 的调用都会创建一个新的 NSCalendar 实例。
  • 每一段 SQLite 语句都是一个段被编译的程序,调用 sqlite3_prepare 将编译 SQLite 查询到字节码,使用 sqlite_bind_int 绑定参数到 SQLite 语句。
  • 为了防止使用 GCD 创建过多的线程,解决方法是创建串行队列, 或者使用带有最大并发数限制的 NSOperationQueue。
  • 线程安全:UIKit只能在主线程执行,除了 UIGraphics、UIBezierPath 之外,UIImage、CG、CA、Foundation 都不能从两个线程同时访问。
  • 不要在主线程执行磁盘、网络、Lock 或者 dispatch_sync、发送消息给其他线程等操作。

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

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

相关文章

windows qt 不能debug_linux配置vlc-qt

vlc-qt 是基于vlc库,用于开发音频视频应用,性能优秀。vlc-qt/vlc-qt​github.com使用vlc-qt首先需要编译vlc-qt (windows可以下载使用编译好的,但是只能用在release模式)(在windows系统中)使用w…

idou老师教你学Istio 27:解读Mixer Report流程

1、概述 Mixer是Istio的核心组件,提供了遥测数据收集的功能,能够实时采集服务的请求状态等信息,以达到监控服务状态目的。 1.1 核心功能 •前置检查(Check):某服务接收并响应外部请求前,先通过E…

mysql删除密码代码_mysql 用户新建、受权、删除、密码修改

mysql 用户新建、授权、删除、密码修改首先要声明一下:一般情况下,修改MySQL密码,授权,是需要有mysql里的root权限的。注:本操作是在WIN命令提示符下,phpMyAdmin同样适用。用户:phplamp 用户数…

KindEditor 上传漏洞致近百个党政机关网站遭植入

开发四年只会写业务代码,分布式高并发都不会还做程序员? >>> 2月21日消息,近日,安恒明鉴网站安全监测平台和应急响应中心监测发现近百起党政机关网站被植入色情广告页面,分析发现被植入色情广告页面的网站都…

Insql 1.8.2 发布,轻量级 .NET ORM 类库

开发四年只会写业务代码,分布式高并发都不会还做程序员? >>> Insql 是一个轻量级的.NET ORM 类库。对象映射基于 Dapper, Sql 配置灵感来自于 Mybatis。 TA 的追求:简洁、优雅、性能与质量 TA 的宗旨:让你用起来感觉到…

教程 | 如何利用C++搭建个人专属的TensorFlow

在开始之前,首先看一下最终成型的代码: 分支与特征后端(https://github.com/OneRaynyDay/autodiff/tree/eigen)仅支持标量的分支(https://github.com/OneRaynyDay/autodiff/tree/master)这个项目是我与 Min…

docker kali安装mysql_kali安装docker(有效详细的教程) ——vulhub漏洞复现 001

前记:博主有着多次安装docker的丰富经验,曾经为了在kali成功安装docker花费不少时间。在kali2016.3一直到最新的kali2019.4都通吃!所以跟着下面的步骤走,绝对不会出错。(该机子此前没装过docker,并且配置好了kali更新源…

PDF文件如何转成markdown格式

百度上根据pdf转makrdown为关键字进行搜索,结果大多数是反过来的转换,即markdown文本转PDF格式。 但是PDF转markdown的解决方案很少。 正好我工作上有这个需求,所以自己实现了一个解决方案。 下图是一个用PDF XChange Editor打开的PDF文件&am…

kangle支不支持PHP_【转载】PHP调用kangle的API

摘要:根据管理的API公布写了一个类封装了一个操作集合,这是一个kangleAPI的一个封...根据管理的API公布写了一个类封装了一个操作集合,这是一个kangleAPI的一个封装吧,是在其他地方看到的,接口包含获取easypanel的信息…

mysql数据库容量和性能_新品速递丨容量盘性能提升超 300%,数据库支持 MySQL 8.0...

2关系型数据库 MySQL Plus支持 MySQL 8.0 内核及 XtraBackup 物理在线迁移方式关系型数据库服务 MySQL Plus 发布新版本 1.0.6 , 新增多项功能,提升了集群自动化运维能力。主要升级有:- 支持 MySQL 8.0 内核:根据官方测试&#xf…

tiger4444/rabbit4444后缀勒索病毒怎么删除 能否百分百恢复

上海某客户中了tiger4444的勒索病毒,找到我们后,一天内全部恢复完成。说了很多关于勒索病毒的事情,也提醒过大家,可总是有人疏忽,致使中招后,丢钱丢面子,还丢工作。 那么要怎样预防呢与处理呢&a…

GPT-5、开源、更强的ChatGPT!

年终岁尾,正值圣诞节热闹气氛的OpenAI写下了2024年的发展清单。 OpenAI联合创始人兼首席执行官Sam Altman在社交平台公布,AGI(稍晚一些)、GPT-5、更好的语音模型、更高的费率限制; 更好的GPTs;更好的推理…

CentOS_7 安装MySql5.7

2019独角兽企业重金招聘Python工程师标准>>> 下载mysql的源 wget http://dev.mysql.com/get/mysql57-community-release-el7-7.noarch.rpm 安装yum库 yum localinstall -y mysql57-community-release-el7-7.noarch.rpm 安装MySQL yum install -y mysql-community-…

性能测试总结(一)---基础理论篇(转载)

随着软件行业的快速发展,现代的软件系统越来越复杂,功能越来越多,测试人员除了需要保证基本的功能测试质量,性能也随越来越受到人们的关注。但是一提到性能测试,很多人就直接连想到Loadrunner。认为LR就等于性能测试&a…

java listen_JavaWeb之Filter、Listener

昨天和大家介绍了一下JSON的用法,其实JSON中主要是用来和数据库交互数据的。今天给大家讲解的是Filter和Listener的用法。一、Listenner监听器1.1、定义Javaweb中的监听器是用于监听web常见对象HttpServletRequest,HttpSession,ServletContext。1.2、监听器的作用监…

java jasypt_Jasypt

软件简介Jasypt这个Java类包为开发人员提供一种简单的方式来为项目增加加密功能,包括:密码Digest认证,文本和对象加密,集成hibernate,SpringSecurity(Acegi)来增强密码管理。Jasypt开发团队推出了Java加密工具Jasypt 1…

ZABBIX监控JAVA日志文件

最近开发人员有一个需求,监控java程序的报错日志,如日志中包含“ERROR”关键字的信息,就邮件告警,以下是具体实现方法。 一、创建模板以上是已经创建好的模板,名为“Template App Java logs”创建应用集二、创建监控项…

如何快速把音乐转成MP3格式

身边有这样一群朋友经常搞音乐,仿佛生活的乐趣只有音乐,不能也能理解,谁没有点自己的爱好呢?但是如果想要在茫茫人海中成为佼佼者,并不是这么容易的,但是我们要在速度上赢更多的人,所以写了这篇…

JavaWeb学习笔记(九)--HttpServletResponse

web服务器接收到客户端的HTTP请求,会针对每一次请求,分别创建一个用于代表请求的request对象和代表响应的response对象。 request和response对象既然代表请求和响应,那我们要获取客户端提交过来的数据,只需要找request对象即可。要…

centos 6.5 yum java_Centos6.5 yum 安装jdk1.8

centos 6.5 安装卸载jdk-- 查看有没有预装jdk版本java -version-- 查看已安装的版本rpm -qa|grep java-- 卸载预装版本 rpm -e --nodeps 命令卸载rpm -e --nodeps java-1.7.0-openjdk-1.7.0.45-2.4.3.3.el6.x86_64-- 查找可以安装的jdk列表yum search java | grep -i --color J…