Android 性能优化 - 稳定性优化

本文总结了Android性能优化的多个方面,包括APK瘦身、启动速度、稳定性、内存和流畅度优化。针对APP稳定性,详细阐述了Crash和ANR的定义,以及如何通过设置Java层和Native层的异常处理器来治理Crash。对于ANR的治理,介绍了ANR的工作原理、监控方法和分析策略。推荐了今日头条的ANR优化实践系列文章作为进一步学习资源。
摘要由CSDN通过智能技术生成

系列文章

APP 稳定性的维度

app 稳定一般指的是 app 能正常运行, app 不能正常运行的情况分为两大类,分别是 CrashANR

Crash:运行过程中发生的错误,是无法避免的。

ANR:应用再运行时,由于无法再规定的时间段内响应完,系统做出的一个操作。

如何治理 Crash

应用发生 Crash 是由于应用在运行时,应用产生了一个未处理的异常(就是没有被 try catch 捕获的异常)。这会导致 app 无法正常运行。

如果需要解决的话,就需要知道这个未处理的异常是在哪里产生的,一般是通过分析未处理的异常的方法调用堆栈来解决问题。

Android APP 可以分为 2 层,Java 层和 Native 层。所以如何捕获需要分开说。

Java 层获取未处理的异常的调用堆栈

这个需要了解 Java 虚拟机是如何把一个未捕获的异常报上来的。

未捕获的异常,会沿着方法的调用链依次上抛,直到 ThreadGroupuncaughtException 方法

    public void uncaughtException(Thread t, Throwable e) {
        if (parent != null) {
            // 递归调用,可以忽略
            parent.uncaughtException(t, e); 
        } else {
            // 交给了 Thread.getDefaultUncaughtExceptionHandler() 来处理未捕获的异常
            Thread.UncaughtExceptionHandler ueh =
                Thread.getDefaultUncaughtExceptionHandler();
            if (ueh != null) {
                ueh.uncaughtException(t, e);
            } else if (!(e instanceof ThreadDeath)) {
                System.err.print("Exception in thread \""
                                 + t.getName() + "\" ");
                e.printStackTrace(System.err);
            }
        }
    }

查阅代码发现,发现 ThreadGroup 最终会给 ThreaddefaultUncaughtExceptionHandler 处理。

private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;

上面的代码显示:ThreaddefaultUncaughtExceptionHandlerThread 类的一个静态变量。

看到这里,如何捕获 Java 层未处理的异常就很清晰了,给 Thread 设置一个新的 defaultUncaughtExceptionHandler,在这个新的defaultUncaughtExceptionHandler 里面收集需要的信息就可以了。

需要注意的一点是 旧的 defaultUncaughtExceptionHandler 需要保存下来,然后新的 defaultUncaughtExceptionHandler 收集信息后,需要再转给旧的 defaultUncaughtExceptionHandler 继续处理。

Native 层获取未处理的异常的相关信息

Java 层如何收集未处理的异常的信息说过了,我们来看看 Native 层发生未处理的异常的话,是如何处理的。 Native 层的处理,需要掌握 linux 的一些知识,由于本人不是特别了解 linux ,这里就直接参考别人的文章了。如果有错误,还请指正。

本人通过查阅资料发现,Native 层如果发生未处理的异常(注:如果 Native 层捕获了异常,是可以通过 JNI 抛到 Java 层去处理的) ,系统会发出信号给 Native 层,在 Native 层如果要收集未处理的异常信息,就需要注册对应信号的处理函数。当发生异常的时候,Native 层会收到信息,然后通过处理器来收集信息。

注册信号处理函数如下:

#include <signal.h> 
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));
  • signum:代表信号编码,可以是除SIGKILL及SIGSTOP外的任何一个特定有效的信号,如果为这两个信号定义自己的处理函数,将导致信号安装错误。
  • act:指向结构体sigaction的一个实例的指针,该实例指定了对特定信号的处理,如果设置为空,进程会执行默认处理。
  • oldact:和参数act类似,只不过保存的是原来对相应信号的处理,也可设置为NULL。

有了信号处理函数,后面还要做的事情就是收集信息了,由于本人不是很熟悉 Native 的开发,这里就不展开说了了,大家可以参考 Android 平台 Native 代码的崩溃捕获机制及实现

如何治理 ANR

ANRApplicatipon No Response 的简称。如果应用卡死或者响应过慢,系统就会杀死应用。为什么要杀死应用?其实也很好理解,如果不杀死应用,大家会以为系统坏了。

那我们如何监控 ANR 呢?以及我们如何分析 ANR 的问题呢?常见的导致 ANR 的原因有哪些呢?

首先,ANR 的原理是 AMSUI 操作开始的时候,会根据 UI 操作的类型开启一个延时任务,如果这个任务被触发了,就表示应用卡死或者响应过慢。这个任务会在 UI 操作结束的时候被移除。

然后,如何分析 ANR 问题呢?

一般 ANR 发生的时候, logcat 里面会打印 ANR 相关的信息,过滤关键字 ANR 就可以看到,这里不做详细分析,可以参考后面的文章。

然后一般会在 /data/anr 目录下面生成 traces.txt 文件,里面一般包含了 ANR 发生的时候,系统和所有应用的线程等信息(需要注意的是,不同的 rom 可能都不一样),通过 logcat 打印的信息和 traces.txt 里面的信息,大部分的 ANR 可以分析出原因,但是呢,也有相当一部分的 ANR 问题无法分析,因为 logcattraces.txt 提供的信息有限,有时候甚至没有特别有用的信息,特别是 Android 的权限收紧, traces.txt 文件在高 Android 版本无法读取,给 ANR 问题的分析增加了不少的困难。不过好在最近发现头条给 ANR 写了一个系列的文章,里面对 ANR 问题的治理方法,个人觉得很好,这里引用一下。

本人之前写过一个小的性能监测的工具,其中有监控 UI 线程 Block 的功能,考虑后续加入头条的 ANR 监测机制,等后续完成了,在做一个详细的总结吧。这次的总结就写到这里。

联系我

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值