Android崩溃优化(崩溃分类、原理分析以及解决)

作为技术人员,我们不应该盲目追求崩溃率这一个数字,应该以用户体验为先,如果强行去掩盖一些问题往往更加适得其反。我们不应该随意使用 try catch 去隐藏真正的问题,要从源头入手,了解崩溃的本质原因,保证后面的运行流程。在解决崩溃的过程,也要做到由点到面,不能只针对这个崩溃去解决,而应该要考虑这一类崩溃怎么解决和预防。(附github项目demo参考项目)

一、Android 的两种崩溃

我们都知道,Android 崩溃分为 Java 崩溃和 Native崩溃。

简单来说,Java 崩溃就是在 Java 代码中,出现了未捕获异常,导致程序异常退出。那 Native 崩溃一般都是因为Native代码中访问非法地址或者是地址对齐出现问题,再或者是发生程序主动abort,这些都会产生对应的signal信号,导致程序异常退出。所以,“崩溃”就是程序出现异常,而一个产品的崩溃率,跟我们如何捕获、处理这些异常有比较大的关系。Java 崩溃的捕获比较简单,但是很多同学对于如何捕获Native 崩溃还是一知半解,下面我就重点介绍 Native 崩溃的捕获流程和难点。

1、Native崩溃捕获流程(Native 崩溃机制)

(1)编译端。编译 C/C++ 代码时,需要将带符号信息的文件保留下来。

(2)客户端。捕获到崩溃时候,将收集到尽可能多的有用信息写入日志文件,然后选择合适的时机上传到服务器。

(3)服务端,读取客户端上报的日志文件,寻找适合的符号文件,生成可读的C/C++调用栈。

2、Native崩溃捕获的难点

Chromium 的Breakpad是目前 Native崩溃捕获中最成熟的方案,所以核心就是保证客户端在各种极端情况下依然可以生成崩溃日志,因为崩溃时,程序处于不安全状态,很可能发生二次崩溃,那么生成崩溃日志主要一些棘手情况:

情况一:文件句柄泄露,导致创建文件日志失败怎么办?应对方式:我们需要提前申请文件句柄fd预留,防止出现这种情况。

情况二:因为栈溢出了导致日志生成失败怎么办?应对方式:为了防止栈溢出导致进程没有空间创建调用栈执行处理函数,我们通常会使用常见的 signalstack。在一些特殊情况,我们可能还需要直接替换当前栈,所以这里也需要在堆中预留部分空间。

情况三:整个堆的内存都耗尽了导致日志生成失败,怎么办?应对方式:这个时候我们无法安全地分配内存,也不敢使用 stl 或者 libc 的函数,因为它们内部实现会分配堆内存。这个时候如果继续分配内存,会导致出现堆破坏或者二次崩溃的情况。Breakpad 做的比较彻底,重新封装了Linux Syscall Supportÿ

你可能感兴趣的:(Android性能优化,Android,Native,crash,崩溃优化,Breakpad,trace)