App性能优化之稳定性优化;十分钟带你了解Crash治理

JavaWeb程序在运行的过程中,只要还有其他线程运行,JVM虚拟机就不会关闭,进程就不会结束。但是在Android App的运行过程中,不论是主线程还是子线程,或是三方库的子线程,只要发生异常,就会引起应用崩溃。原因是JavaWeb程序中没有设置默认的线程异常处理器,而Android系统为每一个Android App进程都设置了默认的线程异常处理器。

五、Crash的影响

Crash率是衡量一个App口碑好坏的重要指标之一。如果忽略了它的存在,它就会得寸进尺,愈演愈烈,最后造成大量用户的流失,进而会带来无法估量的损失。

六、Crash治理原则

对于Crash的治理,我们尽量遵守以下三点原则:

1、由点到面。一个Crash发生了,我们不能只针对这个Crash的去解决,而要去考虑这一类Crash怎么去解决和预防。只有这样才能使得这一类Crash真正被解决。

2、异常不能随便吃掉。随意的使用try-catch,只会增加业务的分支和隐蔽真正的问题,要了解Crash的本质原因,根据本质原因去解决。catch的分支,更要根据业务场景去兜底,保证后续的流程正常。

3、预防胜于治理。当Crash发生的时候,损失已经造成了,我们再怎么治理也只是减少损失。尽可能的提前预防Crash的发生,可以将Crash消灭在萌芽阶段。

七、Crash治理分类

##(一) 常规的Crash治理

常规Crash发生的原因主要是由于开发人员编写代码不小心导致的。解决这类Crash需要由点到面,根据Crash引发的原因和业务本身,统一集中解决。常见的Crash类型包括:空节点、角标越界、类型转换异常、实体对象没有序列化、数字转换异常、Activity或Service找不到等。这类Crash是App中最为常见的Crash,也是最容易反复出现的。在获取Crash堆栈信息后,解决这类Crash一般比较简单,更多考虑的应该是如何避免。下面介绍两个我们治理的量比较大的Crash。

NullPointerException空指针异常

1、NullPointerException是我们遇到最频繁的,造成这种Crash一般有两种情况:

  • 对象本身没有进行初始化就进行操作。
  • 对象已经初始化过,但是被回收或者手动置为null,然后对其进行操作。

2、两种情况对应的解决方法:

针对第一种情况导致的原因有很多,可能是开发人员的失误、API返回数据解析异常、进程被杀死后静态变量没初始化导致,我们可以做的有:

  • (1)对可能为空的对象做判空处理。
  • (2)养成使用@NonNull和@Nullable注解的习惯。
  • (3)尽量不使用静态变量,万不得已使用SharedPreferences来存储。
  • (4)考虑使用Kotlin语言。

针对第二种情况大部分是由于Activity/Fragment销毁或被移除后,在Message、Runnable、网络等回调中执行了一些代码导致的,我们可以做的有:

  • (1)Message、Runnable回调时,判断Activity/Fragment是否销毁或被移除;加try-catch保护;Activity/Fragment销毁时移除所有已发送的Runnable。
  • (2)封装LifecycleMessage/Runnable基础组件,并自定义Lint检查,提示使用封装好的基础组件。
  • (3)在BaseActivity、BaseFragment的onDestory()里把当前Activity所发的所有请求取消掉。

IndexOutOfBoundsException角标越界异常

这类Crash常见于对ListView的操作和多线程下对容器的操作。

1、针对ListView中造成的IndexOutOfBoundsException,经常是因为外部也持有了Adapter里数据的引用(如在Adapter的构造函数里直接赋值),这时如果外部引用对数据更改了,但没有及时调用notifyDataSetChanged(),则有可能造成Crash,对此我们封装了一个BaseAdapter,数据统一由Adapter自己维护通知, 同时也极大的避免了The content of the adapter has changed but ListView did not receive a notification,这两类Crash目前得到了统一的解决。

2、很多容器是线程不安全的,所以如果在多线程下对其操作就容易引发IndexOutOfBoundsException。常用的如JDK里的ArrayList和Android里的SparseArray、ArrayMap,同时也要注意有一些类的内部实现也是用的线程不安全的容器,如Bundle里用的就是ArrayMap。

(二) 系统级Crash治理/特定机型的崩溃治理

众所周知,Android的机型众多,碎片化严重,各个硬件厂商可能会定制自己的ROM,更改系统方法,导致特定机型的崩溃。发现这类Crash,主要靠云测平台配合自动化测试,以及线上监控,这种情况下的Crash堆栈信息很难直接定位问题。下面是常见的解决思路:

1、尝试找到造成Crash的可疑代码,看是否有特异的API或者调用方式不当导致的,尝试修改代码逻辑来进行规避。

2、通过Hook来解决,Hook分为Java Hook和Native Hook: Java Hook主要靠反射或者动态代理来更改相应API的行为,需要尝试找到可以Hook的点,一般Hook的点多为静态变量,同时需要注意Android不同版本的API,类名、方法名和成员变量名都可能不一样,所以要做好兼容工作; Native Hook原理上是用更改后方法把旧方法在内存地址上进行替换,需要考虑到Dalvik和ART的差异;相对来说Native Hook的兼容性更差一点,所以用Native Hook的时候需要配合降级策略。

3、如果通过前两种方式都无法解决的话,我们只能尝试反编译ROM,寻找解决的办法。

(三) OOM

OOM是OutOfMemoryError的简称,在常见的Crash疑难排行榜上,OOM绝对可以名列前茅并且经久不衰。因为它发生时的Crash堆栈信息往往不是导致问题的根本原因,而只是压死骆驼的最后一根稻草。

导致OOM的原因大部分如下:

1、内存泄漏,大量无用对象没有被及时回收导致后续申请内存失败。

2、大内存对象过多,最常见的大对象就是Bitmap,几个大图同时加载很容易触发OOM。

进行内存优化方案主要包括:

  1. 避免内存泄露
  2. 避免内存抖动:避免频繁创建大量、临时的、小的局部对象
  3. 图片Bitmap相关:释放资源、适配屏幕、解码方式、图片缓存
  4. 提高代码质量 & 减少代码数量
  5. 日常不正确使用:ListView的缓存复用、尽量少用多进程、依赖注入框架等

(四) 依赖库的问题(第三方SDK或者服务的问题)

Android App经常会依赖很多AAR,每个AAR可能有多个版本,打包时Gradle会根据规则确定使用的最终版本号(默认选择最高版本或者强制指定的版本),而其他版本的AAR将被丢弃。如果互相依赖的AAR中有不兼容的版本,存在的问题在打包时是不能发现的,只有在相关代码执行时才会出现,会造成NoClassDefFoundError、NoSuchFieldError、NoSuchMethodError等异常。

A和B两个业务库都依赖了map.aar,一个是1.0版本,一个是2.0版本,默认最终打进APK的只有map.aar 2.0版本,这时如果A库里用到的map库里的某个类/方法,但在2.0版本中被删除了,运行时就可能发生异常,虽然SDK在升级时会尽量做到向下兼容,但很多时候尤其是第三方SDK是没法得到保证的。

在这问题在HXB5.0 App里出现过,梆梆加固升级和蚂蚁金服SDK出现兼容问题,导致App闪退。也不明白为什么要用梆梆加固,对APK加固有用吗?我觉得是更是对安全问题的一个甩锅,哈哈哈。

八、Crash的预防实践&止损

(一) 预防实践

单纯的靠约定或规范去减少Crash的发生是不现实的。约定和规范受限于组织架构和具体执行的个人,很容易被忽略,只有靠工程架构和工具才能保证Crash的预防长久的执行下去。

1、工程架构对Crash率的影响

  • 业务模块的划分
  • 页面跳转路由统一处理页面跳转
  • 网络层统一处理API脏数据

2、大图监控

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
的朋友可以戳我获取!!**](https://bbs.csdn.net/topics/618165277)

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值