返回

ANR 优化实践系列分享 - 实例剖析集锦

Android

从单核时代一路发展至今,APP产品形态早已日趋复杂,从单纯的业务场景,已经逐步演变成了与数据层、服务层、中间件层以及底层系统等紧密结合的大型软件工程项目。过往移动 APP 开发者只需要专注于自身业务逻辑的实现即可,但随着近年来终端硬件的突飞猛进,系统 API 功能的不断扩充,客观上对开发者也提出了更高的要求。想满足业务快速迭代的需求同时保持稳定的产品质量,需要开发者具备系统级的思维和系统级的代码设计能力,能够通过不断的优化来提升产品的使用体验。

ANR 优化剖析

ANR (Application Not Responding),即应用无响应,是指在一定时间间隔内系统未收到应用进程响应。对于不同的系统,默认的 ANR 超时时间各不相同。在 Android 系统中,ANR 的默认超时时间为 5 秒。为了避免出现卡顿的感知,在系统底层,往往都会对一些耗时操作做硬超时限制。例如,Android 系统中,消息队列的发送和取出默认超时时间均为 10 秒。超过超时时间,系统将直接抛出 ANR 异常。可以说,ANR 问题已经成为开发者在日常开发过程中遇到的最常见的性能问题之一。

针对 ANR 的优化实践,实际上就是如何识别和优化主线程超时任务。目前对于 ANR 的优化,主流的方法是应用侧通过设置系统属性来收集 ANR 信息,进而进行优化。常用的方法有两种:

  1. 通过设置属性 dalvik.vm.useragent,让系统将 ANR 信息输出到 logcat 日志中。收集到 ANR 日志之后,再通过统计分析工具对 ANR 日志中的堆栈进行解析,确定引起 ANR 的函数调用链。
  2. 通过设置属性 dropbox.startService,让系统将 ANR 信息保存到 dropbox 文件中。dropbox 文件是以二进制格式存储的,需要借助 bugreport 命令来导出 dropbox 文件,再通过 dropbox 解析工具对文件中的 ANR 信息进行解析。

常见 ANR 优化场景

接下来,我们用较多的篇幅对 ANR 产生的原因进行分析,以便更好地解决和优化。

1. 消息队列深度堆积

消息队列深度堆积问题,简单来说就是消息队列中的消息过多,超过了系统处理的阈值,从而导致消息队列被阻塞,应用程序无法响应用户操作。这种场景在实际上也比较常见,尤其是当应用处理消息的速度慢于消息产生的速度时,就很容易出现消息队列深度堆积的情况。

2. CPU 资源不足

当设备的 CPU 资源不足时,也会导致 ANR 问题的发生。例如,当设备运行多个占用 CPU 资源较多的应用程序时,或者当设备正在执行耗时较长的任务时,就很容易出现 CPU 资源不足的情况。

3. 内存不足

当设备的内存不足时,也会导致 ANR 问题的发生。例如,当设备运行多个占用内存较多的应用程序时,或者当设备正在执行耗时较长的任务时,就很容易出现内存不足的情况。

4. I/O 操作超时

当设备进行 I/O 操作时,如果 I/O 操作超时,也会导致 ANR 问题的发生。例如,当设备正在读取或写入数据时,如果 I/O 操作超时,就很容易出现 ANR 问题的发生。

5. 网络请求超时

当设备进行网络请求时,如果网络请求超时,也会导致 ANR 问题的发生。例如,当设备正在从服务器获取数据时,如果网络请求超时,就很容易出现 ANR 问题的发生。

如何避免 ANR

为了避免 ANR 的发生,我们可以从以下几个方面入手:

1. 优化消息处理速度

我们可以通过以下几种方法来优化消息处理速度:

  • 使用更高效的消息队列实现。
  • 减少消息队列中消息的数量。
  • 提高消息处理的优先级。

2. 优化 CPU 资源使用

我们可以通过以下几种方法来优化 CPU 资源使用:

  • 避免长时间占用 CPU 资源。
  • 将耗时较长的任务分解成多个较小的任务,以便在不同的线程中执行。
  • 使用更高效的算法来实现任务。

3. 优化内存使用

我们可以通过以下几种方法来优化内存使用:

  • 避免创建过多的对象。
  • 复用对象。
  • 释放不再使用的对象。

4. 优化 I/O 操作

我们可以通过以下几种方法来优化 I/O 操作:

  • 使用更高效的 I/O 库。
  • 减少 I/O 操作的次数。
  • 提高 I/O 操作的优先级。

5. 优化网络请求

我们可以通过以下几种方法来优化网络请求:

  • 使用更高效的网络请求库。
  • 减少网络请求的次数。
  • 提高网络请求的优先级。

结语

ANR 问题是移动开发中常见的性能问题之一,也是一个比较复杂的问题。导致 ANR 发生的原因有很多,包括消息队列深度堆积、CPU 资源不足、内存不足、I/O 操作超时、网络请求超时等。为了避免 ANR 的发生,我们可以从优化消息处理速度、优化 CPU 资源使用、优化内存使用、优化 I/O 操作、优化网络请求等几个方面入手。