优化 App 的启动速度

App 的启动速度不仅影响我们调试,也直接关系到用户体验。之前有些很久没有打开过的项目,需要花费很长的时间才完成编译;对应的 App 在点击后,许久才出现启动画面。你是否为这些问题苦恼过呢?

这是我观看 WWDC2016 Sessions406 《Optimizing App Start Time》的博客笔记。虽然没有字幕听起来很吃力,但光看 Slide 还是有不少收获的。原文有点长,包括理论是实践两部分,为了方便阅读这里只放出一部分。

Mach-O 文件是如何被加载的

在 mian() 函数执行之前,操作系统为我们做了什么?

exec() -> main()

exec()执行过程:
内核随机分配一段可用的内存给应用程序。但有个规则,即不分配低地址的内存空间,该地址空间大小由处理器的位数决定,情况如下:

  • 32位处理器保留 4K

  • 64位处理器保留 4G

低地址保留,用于保存空指针、异常错误信息等。



加载动态库

内存分配完成后,处理器运行动态加载器(Dynamic loader)来加载动态依赖库(dylibs)。

加载过程:

  1. 映射所有的直接依赖库,递归间接调用的依赖库(Map all dependent dylibs,recurse).

  2. 重建所有的图片(Rebase all images).

  3. 绑定所有图片(Bind all images).

  4. 准备代码层面的加载(ObjC prepare images)

  5. 执行初始化方法(Run initializes).



1. 加载动态库

直接加载:

  • 解析所有的动态库

  • 找出需要的 mach-O 文件

  • 打开并读取文件

  • 认证 mach-O 文件

  • 登记代码签名

  • 为每个 segment 调用 mmap() 映射函数

递归加载:
当所有直接依赖库加载完毕后,还存在直接依赖库依赖于其他库的情况。递归加载间接依赖库,一般 App 需要加载 100 到 400 个动态库!其中绝大多数为系统库,苹果已经最优化了系统库的加载。

2. 重建(Rebasing)

将图片资源根据其地址进行加载,重建信息被编码在 LINKEDIT segment 中。重建的过程按照地址顺序执行,所以可以被内核预取。

3. 绑定(Binding)

应用程序对动态库的引用只是字符层(symbol)面上,绑定过程中需要加载器通过函数名来查找,相对于重建这个过程需要更多的计算。


4. ObjC 准备阶段
  • 完成重建和绑定后的配置工作

  • 登记定义的 ObjC 类

  • 更新实例变量对应的内存位置

  • 分类的方法被插入到主类

5. 初始化(Initializer)
  • 静态分配内存的对象的初始化

  • 调用 +load 方法

  • 调用相关联的动态库

  • 最后,执行 main()函数


启动优化

对于不同的设备启动速度都不相同,苹果认为完美的启动时间是在 400 毫秒以内。App 的最大允许启动时间为20秒,如果超过这个时间就会被 Killed。

我们可以通过编辑工程的 Schemes 来打印 App 的启动中各项时间花费,从而来分析和优化启动过程。
在 Arguments -> Environment Variables 中加入 DYLY_PRINT_STATISTICS


设置后,控制台部分项时间花费输出:


1. 加载动态库

加载动态库需要很大的开销,解决方法是尽可能减少引入不必要的动态库,合并现有可操作的动态库,使用静态文件,使用懒加载等

2. 重建和绑定过程
  • 减少指针变量的使用

  • 减少 Objective-C 类

  • 减少 C++ 虚基类的使用(少见)

  • 建议使用 Swift 结构体

  • 尽可能将属性设置为只读

3. 初始化
  • 将 +load 函数的操作尽可能在 +initialize 方法中执行

  • 简化 C++ 构造函数

  • 不要在初始化方法里面调用 dlopen()

  • 不要在初始化方法里面创建线程

+initialized 会在任何类加载之前被调用,而 +load 是所在类被加载到系统的时候被调用,这通常比 +initialized 调用的时机要早。在 +load 函数里面做操作会延缓系统的启动时间。

dlopen() 函数用于打开 Bundle 尽可能的延迟读取本地的 Bundld 资源,也有利于加快启动速度。

线程的创建需要很大的开销,不要在 App 启动的过程创建子线程。

<think>好的,我现在需要回答用户关于如何在Android 7上优化App启动速度的问题。首先,我需要回忆一下Android启动优化的基本知识,并结合用户提供的引用内容来组织回答。用户已经给出了一些引用资料,我需要确保正确引用这些内容,同时遵循系统级指令中的格式要求。 首先,Android的启动优化通常涉及冷启动、温启动和热启动。用户提到的引用[4]指出冷启动耗时最长,所以优化重点应该在冷启动上。接下来,引用[2]提到了通过设置启动器图标直接启动特定界面,减少热启动时间,这可能涉及到Intent Filter的配置。另外,引用[3]和[5]提到了异步加载和延迟加载UI组件,比如使用AsyncTask来处理后台任务,避免主线程阻塞。 然后,我需要考虑Android 7系统的特性,是否有特定的优化技巧适用于该版本。例如,Android 7引入了Doze模式和应用待机模式,可能会影响后台进程,但启动优化主要关注启动过程本身。可能需要检查是否有系统级别的变更影响启动时间,比如后台检查或权限处理。 接下来,整理优化步骤。根据引用资料,可能的优化点包括:减少主线程任务、异步初始化、延迟初始化、优化启动主题、避免I/O操作、使用工具分析等。需要将这些点结构化,分点说明,并确保每个点都有对应的引用支持。 另外,用户提供的引用[1]提到性能优化的重要性,可以作为引言部分。引用[2]的启动器图标设置可能涉及启动Activity的优化,引用[3]和[5]的异步处理是关键步骤,引用[4]强调冷启动优化的重要性。 需要注意,所有行内数学表达式如公式要用$...$,但这里可能用不上。独立公式可能需要用$$...$$,但问题可能不涉及数学公式。所以主要关注中文回答、引用标识的正确使用、代码块的格式以及相关问题的生成。 最后,生成相关问题时要围绕启动优化的延伸,比如工具使用、其他版本优化、异步任务注意事项等。</think>### Android 7应用启动性能优化技巧 Android应用的启动速度直接影响用户体验。以下是针对Android 7系统的优化技巧,结合冷启动优化、异步任务处理和资源加载策略: --- #### 1. **减少冷启动时间** 冷启动是应用从零开始加载的过程,耗时最长。优化方向包括: - **启动主题优化**:使用透明背景或占位图主题,避免启动时白屏/黑屏。 示例:在`styles.xml`中定义启动主题: ```xml <style name="AppTheme.Launcher"> <item name="android:windowBackground">@drawable/launch_background</item> </style> ``` 在`AndroidManifest.xml`中为启动Activity指定该主题: ```xml <activity android:name=".MainActivity" android:theme="@style/AppTheme.Launcher"> </activity> ``` 进入主界面后恢复默认主题[^4]。 - **避免主线程阻塞**:将初始化任务(如数据库、网络预加载)迁移到子线程或延迟加载[^5]。 --- #### 2. **异步初始化与延迟加载** - **使用`AsyncTask`或线程池**:将非核心任务(如日志模块、第三方SDK)异步化。 示例代码: ```java new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { // 初始化非关键任务 return null; } }.execute(); ``` - **延迟加载次要组件**:通过`Handler.postDelayed()`或`View.post()`延后初始化非紧急功能(如广告、统计)[^3]。 --- #### 3. **优化启动Activity配置** - **精简启动Activity布局**:减少布局层级,用`ViewStub`懒加载复杂视图。 - **避免直接启动主界面**:通过`<intent-filter>`指定轻量级Activity作为启动入口,减少初始化负担[^2]。 --- #### 4. **监控与分析工具** - **Traceview和Systrace**:分析启动过程中的CPU占用和线程阻塞点。 - **ADB命令测量启动时间**: ```bash adb shell am start -W com.example.app/.MainActivity ``` 输出结果中的`TotalTime`即为启动耗时。 --- #### 5. **其他关键优化点** - **控制多进程启动**:Android 7上多进程会并行初始化,但可能增加资源竞争,需评估必要性。 - **禁用调试工具依赖**:移除`StrictMode`和调试日志的线上版本。 - **优化资源加载**:压缩图片,避免APK中未使用的资源。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值