Android客户端性能异常类
影响app体验的通用类问题可以分为两大类:超时和崩溃。
超时 (Time Out)
没有在用户的预期内及时的响应用户的请求和交互。
分为:较轻的影响是UI的卡顿掉帧;
比较大的影响是ANR(Application Not Responding):能恢复的ANR;不能恢复的ANR-永久性卡死问题。
超时的原因:
- UI线程中block的操作;
- IO/数据库/网络耗时操作;
- 复杂不合理的布局;
- overdraw的过度绘制;
- 内存使用异常导致的卡顿,例如内存抖动或泄露等导致GC的次数增多,消耗在GC的时间长,CPU绘制时间会短;
- 不合理的异步(会导致CPU占用互斥资源);
崩溃 (Crash)
在某些场景下,满足的条件未满足或者需要的资源没有拿到,出现的未预期的运行时异常。
类型 | 破坏性 | 解决难度 |
---|---|---|
ANR | 低 | 中 |
Java Crash | 低 | 低 |
Native Crash | 低 | 低 |
Java崩溃
可分为三大类:check异常,runtime异常,错误;
这里的crash都会抓到完整的调用栈信息,且大部分和业务侧的逻辑使用相关
- checked异常:由编程与环境互动造成程序在运行时出错,编译时异常
- Error类:通常是指Java的内部错误以及如资源耗尽的错误
- runtime异常:运行时异常
常见原因:
Native崩溃
主动类:运行时框架代码或业务代码发现的状态异常,代码运行过程中主动触发;这类异常在预期范围内,通过此类方法暴露问题。例如:资源不足,内存超过阈值等。
被动类:在运行时执行一些指令或者访问某些内存地址被动触发的;不在预期范围内;比如:野指针,多线程操作文件没有同步保护等等。
Native崩溃使用信号(singal)机制返回信息:
Android native崩溃产生常见信号大致有以下几类:
- SIGABRT
- SIGSTKFLT
- SIGTARP
- SIGSEGV
- SIGBUS
- SIGILL
SIGABRT
SIG是信号名的通用前缀。ABRT是abort program的缩写;由调用abort函数产生,进程非正常退出。当用户态的 Native 代码在运行过程中发现了某些状态异常,就会给自己(线程)发送信号触发自杀流程。
常见问题有:
-
异常流程:当系统因内存不足无法分配buffer,代码就选择了调用宏函数,自杀了
-
虚拟内存泄漏:32位APP的地址空间只有4GB,因此程序运行过程中内存用的多了容易引起OOM。64位APP地址空间几乎无限大,基本不存在OOM的问题;
通过获取崩溃时的虚拟内存大小,就知道是否有内存泄漏;内存泄漏关键字
另外,因为是SIGABRT类型,虚拟内存泄漏也有常见的Abort Message关键字:- Out of memory
- Failed to map PBO
- failed to allocate TLS
-
虚拟机异常
- Thread suspend timeout(线程挂起时间过长)
- local reference table overflow (本地引用表溢出)
- java.lang.OutOfMemoryError
- 文件描述符泄漏
- 堆内存破坏
SIGTKFLT
协处理器的栈异常。这类异常是dvm虚拟机特有的。dvm虚拟机在GC或者打印trace文件时会suspend所有线程,如果有suspend失败的线程,就会给这个线程发送SIGSTKFLT信号。
SIGTRAP
SIGTRAP是通过汇编指令bkpt触发CPU的预取指异常,并在内核态的预取指异常处理函数中,给当前线程发送SIGTRAP信号。
汇编指令bkpt(break point的缩写),用于产生软件断点中断,以便软件调试时使用。
SIGSEGV
非法内存操作,与下面的SIGBUS不同,是对合法地址的非法访问,比如访问没有读权限的内存,向没有写权限的地址写数据等。
SIGSEGV类错误出现在CPU的虚拟地址转换物理地址的过程,分两种不同情况。
- SEGV_MAPERR:当前执行的指令访问的内存地址未映射到当前进程地址空间
- SEGV_ACCERR:当前执行的指令访问的内存地址无访问权限(读、写、执行)
SEGV_MAPERR:
- 字符串溢出:寄存器中不够存储字符串长度
- 空对象:底层某个对象null了
- PC跑飞:一般是程序(PC寄存器)跑飞或者栈(SP寄存器)被破坏
SIGBUS
非法地址,包括内存地址对齐出错,比如访问一个4字节的整数, 但其地址不是4的倍数。细分为:
- BUS_ADRALN:当前执行的指令访问的内存地址不符合指令的对齐规范
- 这类异常通常是内存踩踏导致的偶现的随机问题,概率极小
- BUS_ADRERR:当前执行的指令访问的文件映射地址的缺页异常错误
- 这类异常和文件的读写相关
SIGILL
当前执行的指令是CPU无法识别的非法指令时,会触发SIGILL信号。根据异常指令的来源分三种情况。
- udf指令:此指令 arm cpu无法识别
- 指令被破坏:生成指令时(ROM or RAM的BIt位反转)出错,导致RAM或者ROM中的指令异常;属于硬件出错
- 指令集错误:CPU错误解析指令