Android开发高手课
张绍文
前微信高级工程师,Tinker负责人
立即订阅
12609 人已学习
课程目录
已完结 61 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 焦虑的移动开发者该如何破局?
免费
导读 (1讲)
导读 | 如何打造高质量的应用?
模块一 高质量开发 (25讲)
01 | 崩溃优化(上):关于“崩溃”那些事儿
02 | 崩溃优化(下):应用崩溃了,你应该如何去分析?
03 | 内存优化(上):4GB内存时代,再谈内存优化
04 | 内存优化(下):内存优化这件事,应该从哪里着手?
05 | 卡顿优化(上):你要掌握的卡顿分析方法
06 | 卡顿优化(下):如何监控应用卡顿?
06补充篇 | 卡顿优化:卡顿现场与卡顿分析
07 | 启动优化(上):从启动过程看启动速度优化
08 | 启动优化(下):优化启动速度的进阶方法
09 | I/O优化(上):开发工程师必备的I/O优化知识
10 | I/O优化(中):不同I/O方式的使用场景是什么?
11 | I/O优化(下):如何监控线上I/O操作?
12 | 存储优化(上):常见的数据存储方法有哪些?
13 | 存储优化(中):如何优化数据存储?
14 | 存储优化(下):数据库SQLite的使用和优化
15 | 网络优化(上):移动开发工程师必备的网络优化知识
16 | 网络优化(中):复杂多变的移动网络该如何优化?
17 | 网络优化(下):大数据下网络该如何监控?
18 | 耗电优化(上):从电量优化的演进看耗电分析
19 | 耗电优化(下):耗电的优化方法与线上监控
20 | UI 优化(上):UI 渲染的几个关键概念
21 | UI 优化(下):如何优化 UI 渲染?
22 | 包体积优化(上):如何减少安装包大小?
23 | 包体积优化(下):资源优化的进阶实践
24 | 想成为Android高手,你需要先搞定这三个问题
模块二 高效开发 (9讲)
25 | 如何提升组织与个人的研发效能?
26 | 关于编译,你需要了解什么?
27 | 编译插桩的三种方法:AspectJ、ASM、ReDex
28 | 大数据与AI,如何高效地测试?
29 | 从每月到每天,如何给版本发布提速?
30 | 数据评估(上):如何实现高可用的上报组件?
31 | 数据评估(下):什么是大数据平台?
32 | 线上疑难问题该如何排查和跟踪?
33 | 做一名有高度的移动开发工程师
模块三 架构演进 (9讲)
34 | 聊聊重构:优秀的架构都是演进而来的
35 | Native Hook 技术,天使还是魔鬼?
36 | 跨平台开发的现状与应用
37 | 移动开发新大陆:工作三年半,移动开发转型手游开发
38 | 移动开发新大陆:Android音视频开发
39 | 移动开发新大陆: 边缘智能计算的趋势
40 | 动态化实践,如何选择适合自己的方案?
41 | 聊聊Flutter,面对层出不穷的新技术该如何跟进?
42 | Android开发高手课学习心得
练习Sample跑起来 (8讲)
练习Sample跑起来 | 热点问题答疑第1期
练习Sample跑起来 | 热点问题答疑第2期
练习Sample跑起来 | 热点问题答疑第3期
练习Sample跑起来 | 热点问题答疑第4期
练习Sample跑起来 | ASM插桩强化练习
练习Sample跑起来 | 唯鹿同学的练习手记 第1辑
练习Sample跑起来 | 唯鹿同学的练习手记 第2辑
练习Sample跑起来 | 唯鹿同学的练习手记 第3辑
特别放送 (7讲)
Android JVM TI机制详解(内含福利彩蛋)
专栏学得苦?可能是方法没找对
专栏学得苦?可能你还需要一份配套学习书单
Native下如何获取调用栈?
聊聊Framework的学习方法
Android工程师的“面试指南”
程序员修炼之路 | 设计能力的提升途径
结束语 (1讲)
结束语 | 移动开发的今天和明天
Android开发高手课
登录|注册

01 | 崩溃优化(上):关于“崩溃”那些事儿

张绍文 2018-12-01
在各种场合遇到其他产品的开发人员时,大家总忍不住想在技术上切磋两招。第一句问的通常都是“你们产品的崩溃率是多少?”
程序员 A 自豪地说: “百分之一。”
旁边的程序员 B 鄙视地看了一眼,然后喊到: “千分之一!”
“万分之一” ,程序员 C 说完之后全场变得安静起来。
崩溃率是衡量一个应用质量高低的基本指标,这一点是你我都比较认可的。不过你说的“万分之一”就一定要比我说的“百分之一” 更好吗?我觉得,这个问题其实并不仅仅是比较两个数值这么简单。
今天我们就来聊一聊有关“崩溃”的那些事,我会从 Android 的两种崩溃类型谈起,再和你进一步讨论到底该怎样客观地衡量崩溃这个指标,以及又该如何看待和崩溃相关的稳定性。

Android 的两种崩溃

我们都知道,Android 崩溃分为 Java 崩溃和 Native 崩溃。
简单来说,Java 崩溃就是在 Java 代码中,出现了未捕获异常,导致程序异常退出。那 Native 崩溃又是怎么产生的呢?一般都是因为在 Native 代码中访问非法地址,也可能是地址对齐出现了问题,或者发生了程序主动 abort,这些都会产生相应的 signal 信号,导致程序异常退出
所以,“崩溃”就是程序出现异常,而一个产品的崩溃率,跟我们如何捕获、处理这些异常有比较大的关系。Java 崩溃的捕获比较简单,但是很多同学对于如何捕获 Native 崩溃还是一知半解,下面我就重点介绍 Native 崩溃的捕获流程和难点。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Android开发高手课》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(148)

  • 孙鹏飞 置顶
    关于x86模拟器下无法生成日志的问题是由于clang导致的,需要使用gcc编译,例子的readme里已经补上了解决方法
    2018-12-01
    13
  • 周大军 置顶
    首先感谢下前面同学的优质评论,我遇到一些问题实在搞不定时候,参考评论解决了一些问题。以下是我具体遇到的一些问题,希望能够给用Ubuntu作为开发环境的同学一点帮助。
    PC操作系统:Ubuntu18.04 X64
    AS版本:3.1
    手机:华为V8 8.0系统
    遇到的问题:
    1. 导入项目编译不过:
    Build command failed.
    Error while executing process /home/jayden/Android/Sdk/cmake/3.6.4111459/bin/cmake with arguments {-H/mnt/D.....
    CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage
    CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage
    -- Configuring incomplete, errors occurred!
    解决方法:
    下载cmake 3.6对应的ndk版本,下载ndk12版本( https://dl.google.com/android/repository/android-ndk-r12b-linux-x86_64.zip)解压到sdk路径下,并在local.properties配置上对应的ndk.dir路径。

    2. minidump_stackwalk dump对应的 crash文件时候,报错,如上老师说的,需要自己编译对应环境的源码,所以我选择下载https://github.com/google/breakpad里的depot_tools,然后make install出来自己用。也可以借鉴其他人下载缺失的头文件来编译github上的源码。

    3. addr2line的时候,报错 File format not recognized, Linux的话需要用aarch64-linux-android-4.9,而不是arm-linux-androideabi-4.9 。
     ~/Android/Sdk/android-ndk-r12b/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-addr2line -f -C -e sample/build/intermediates/transforms/mergeJniLibs/debug/0/lib/arm64-v8a/libcrash-lib.so 0x5a0
    Crash()
    /mnt/Data/github/Geek_Android_Improve/Chapter01/sample/src/main/cpp/crash.cpp:10

    作者回复: 赞

    2018-12-06
    7
  • 永远年轻 置顶
    虽然历经阻碍,最终没有 dump 成功,但可以给还没操作的同学一点建议
    1.最好自备梯子,导入工程会很顺利
    2.Smaple 里「补充内容」那几行代码是加到 build.gradle -> andoroid -> defaultConfig 里的
    3.装在 ARM 设备上时提示找不到 "libbreakpad-core.so" , build 一个 apk 就好了
    4.macOS 10.14 删除了 libstdc++.6.dylib 和 libstdc++.dylib 两个动态库,/usr/lib 里的同名文件都是 libstdc++.6.0.9.dylib 的替身,用 minidump_stackwalk 时会提示 「__ZTTNSt7__cxx1118basic_stringstreamIcSt11char_traitsIcESaIcEEE」这个方法找不到,通过 google 搜索都是 Xcode 开发相关的解决方案
    ps 试着下 depot_tools 自己编译,要下载好几个 G 的数据,放弃了。

    作者回复: 这个赞一下。有一个问题就是我们虽然可以提供breakpad tools 编译好的bin放上去,但由于运行环境不同会导致上述缺少动态链接库的问题,所以建议同学自己编译。网上的文章多是提出depottools的编译方案,其实可以使用breakpad的源码直接使用cmake编译。这个在breakpad官方库的doc里有说明

    2018-12-04
    1
    6
  • Owen 置顶
    关于breakpad的学习,结合老师的讲解和自己的爬坑,参照老师的demo,自己写了个自己觉得理解比较通透的总结,欢迎各位大佬指导和建议https://github.com/devzhan/Breakpad
    2018-12-24
    5
  • 答案
    文哥~我发现其实可以不用重新编译minidump_stackwalk,Android自带就有!我是windows系统,在AS安装目录下bin\lldb\bin下。我写了篇文章,亲自试过,也完成了作业!我看大家在评论区都是先编译然后再解析,而且有些学员还碰到各种问题,花了很多时间,所以希望我的经验能够帮助到其他学员,https://www.jianshu.com/p/0bfe7800bdef

    作者回复: 👍

    2019-01-15
    3
    18
  • 东方
    try catch 被滥用,藏的很深,吃掉了异常。曾经因为这个问题,整个团队花了两天时间才挖出来。非常愤怒。想从Java虚拟机异常机制入手,拦截所有的Java异常,然后过滤自己感兴趣的信息。但是虚拟机复杂,无从下手。

    想问一下张老师有什么好的建议?

    作者回复: 一般做法有
    1. 在线程池直接拦截所有的java异常,但是只在正式版本使用,保留灰度包不拦截
    2. 一般crash sdk都提供虽然try catch,但依然会上报到后台的方法。

    2018-12-01
    16
  • 、、cryAllen
    第一步:
    git clone代码,下载安装NDK和CMAKE,在此期间碰到一个问题,就是NDK下载版本太高,导致项目编译不过去,进一步分析,发现ndk-bundle\toolchains文件夹中少了mips64el-linux-android-4.9和mipsel-linux-android-4.9文件,解决方法是下载一个旧的NDK版本,把这两个文件夹复制过去即可。

    第二步:
    接着就run,在手机上跑起来了,点击CRASH,程序崩溃,我进去sdcard中看到了crashDump目录,生成崩溃文件。

    第三步:
    接着运行: ./tools/mac/minidump_stackwalk crashDump/***.dmp >crashLog.txt ,结果又报错了,由于我的系统是Windows,不是Mac,故需要重新编译minidump_stackwalk 工具,解决方法是下载个VMWare虚拟机,装个Unbuntu 系统,然后重新编译,在编译过程中,由于git clone了breakpad源码,会缺少一个thrid_party里的一个less文件夹,名称为linux_syscall_support.h头文件,需要补上即可。

    第四步:
    利用./configure && make
    对源码完成了编译,minidump_stackwalk这个文件在src/processor/目录中,然后运行:
    ./minidump_stackwalk crashDump/***.dmp >crashLog.txt
    大功告成:
    Operating system: Android
                      0.0.0 Linux 3.18.22+ #1 SMP PREEMPT Mon Jun 11 17:42:41 CST 2018 armv8l
    CPU: arm
         ARMv1 ARM part(0x4100d0b0) features: half,thumb,fastmult,vfpv2,edsp,neon,vfpv3,tls,vfpv4,idiva,idivt
         10 CPUs

    GPU: UNKNOWN

    Crash reason: SIGSEGV /SEGV_MAPERR
    Crash address: 0x0
    Process uptime: not available

    Thread 0 (crashed)
     0 libcrash-lib.so + 0x77e
         r0 = 0x00000000 r1 = 0x00000001 r2 = 0xffdb9bdc r3 = 0xf4a57fc0
         r4 = 0x702af968 r5 = 0x6fb3bc10 r6 = 0x12e21970 r7 = 0xffdb9bc8
         r8 = 0x12de5330 r9 = 0xf4a76a00 r10 = 0x12dd28b0 r12 = 0xf36a6fd8
         fp = 0x70536430 sp = 0xffdb9bb4 lr = 0xf36a379b pc = 0xf36a377e
        Found by: given as instruction pointer in context
     1 dalvik-main space (deleted) + 0x5fffe
         sp = 0xffdb9bcc pc = 0x12c60000
        Found by: stack scanning
     2 base.odex + 0x44121f
         sp = 0xffdb9bd0 pc = 0xdf254221
        Found by: stack scanning
     3 dalvik-LinearAlloc (deleted) + 0xf016
         sp = 0xffdb9bd4 pc = 0xeea9a018
        Found by: stack scanning
     4 dalvik-main space (deleted) + 0xd539e
         sp = 0xffdb9be0 pc = 0x12cd53a0
        Found by: stack scanning

    2018-12-06
    1
    12
  • IOT..Yang
    首先,按照github工程的ReadMe流程走一遍,碰到了2个提示,让我安装NDK和CMAKE,我根据提示安装后编译直接就成功了;

    接着就run,在手机上跑起来了,点击CRASH,程序崩溃,我进去sdcard中看到了crashDump目录,但没有生成崩溃文件,看到评论说的,将sample的build.gradle中注释给去掉:
    abiFilters "armeabi-v7a", // "arm64-v8a", "x86" --> abiFilters "armeabi-v7a", "arm64-v8a", "x86"
    我测试了下,成功生成了crash文件(不知道是不是张老师故意制造的障碍~捂手偷笑);

    接着运行: ./tools/mac/minidump_stackwalk crashDump/***.dmp >crashLog.txt ,结果又报错了:
    dyld: Symbol not found: __ZTTNSt7__cxx1118basic_stringstreamIcSt11char_traitsIcESaIcEEE
      Referenced from: /Users/james/Documents/projec/breakpad/Chapter01/./tools/mac/minidump_stackwalk
      Expected in: /usr/lib/libstdc++.6.dylib
     in /Users/james/Documents/projec/breakpad/Chapter01/./tools/mac/minidump_stackwalk
    Abort trap: 6
    评论中老师说到缺少必要的动态链接库导致的,建议我们去编译breakpad源码;

    然后,我去git clone了breakpad源码,利用
    ./configure
    make
    对源码完成了编译,minidump_stackwalk这个文件在src/processor/目录中,然后运行:
    ./minidump_stackwalk crashDump/***.dmp >crashLog.txt
    大功告成,分享下我得成果:
    Operating system: Android
                      0.0.0 Linux 3.18.31-perf-g4fd2040 #1 SMP PREEMPT Tue Dec 4 03:15:19 WIB 2018 aarch64
    CPU: arm64
         8 CPUs

    GPU: UNKNOWN

    Crash reason: SIGSEGV /SEGV_MAPERR
    Crash address: 0x0
    Process uptime: not available

    Thread 0 (crashed)
     0 libcrash-lib.so + 0x600
         x0 = 0x0000007f7583e300 x1 = 0x0000007ff1b88ad4
         x2 = 0x0000007f792e3000 x3 = 0x0000000001e5a140
    2018-12-05
    1
    7
  • 二两五花肉
    老师您好,学习这里的native崩溃处理,是不是得先学习c++,战五渣表示完全看不懂这些

    作者回复: 这块的确会复杂一些,还需要对指令执行机制这些都一定了解

    2018-12-03
    7
  • 克明(Kevin.Tian)
    只有空目录,里面没minidump文件
    2018-12-01
    7
  • X
    你好张老师:
    1.请问像微信这种大项目灰度测试一般是怎么做的? 是开发了专门的sdk么,我所知的一般是给某些渠道包作为灰度包,或者客户端根据服务器的配置来决定启用新功能,但感觉都挺麻烦的。
    2.另外想问张老师个与本节无关的,就是以前做跑步App,发现进程保活很痛苦,想了解下微信的保活手段有哪些,是否真的有白名单这东西?

    作者回复: 1. 有一个专门的性能收集模块,可以根据版本级别这些决定开启哪些采集模块,也可以控制采样率这些参数
    2.微信保活做的很少的,主要的确是厂商的白名单

    2018-12-03
    6
  • 运行生成crashlog文件命令,总是报下面的错误:
    dyld: Symbol not found: __ZTTNSt7__cxx1118basic_stringstreamIcSt11char_traitsIcESaIcEEE
      Referenced from: /Users/Downloads/Chapter01-master/tools/mac/./minidump_stackwalk (which was built for Mac OS X 10.13)
      Expected in: /usr/lib/libstdc++.6.0.9.dylib
     in /Users/Downloads/Chapter01-master/tools/mac/./minidump_stackwalk
    Abort trap: 6
    不知道什么原因?
    2018-12-03
    5
  • gg
    遇到的问题:
    1.googlesource上breakpad源码无法下载
    2.sample中的minidump_stackwalk无法运行
    解决方案:
    1.下载GitHub的镜像源码
    2.自己编译breakpad
    结果:
    成功捕获native异常,并从dump文件中定位到异常代码
    总结:
    看似简单的例子在做的过程中也可能遇到各种问题,动手才能在做的过程中遇到问题,解决问题,提升自己的能力。
    2018-12-03
    5
  • 五花肉小生
    我买了 24 个课了,老师可以说是声音最好听的技术专栏作者了。
    2018-12-01
    5
  • SunnyBird
    项目实践总结:
    1. breakpad 下载问题,官网提供的工具可能是网络环境问题,没有下载下来,可以直接下载 master 分支 tgz 包
    2. third_party/ssl/linux_syscall_support.h 缺失问题,https://chromium.googlesource.com/linux-syscall-support/+/refs/heads/master 同样下载 tgz 包,解压 linux_syscall_support.h 放在项目 third_party/ssl/ 目录
    3. PC 端 minidump_stackwalk 工具,需要用 breakpad 源码编译
    ./configure
    make
    make install

    项目例子地址 : https://github.com/sunnybird/AdvanAndroid/tree/master/BreakpadDemo
    2018-12-03
    4
  • wmj
    bugly里都是native的崩溃,要怎么处理?都是一些信号啥的,无从下手

    作者回复: native异常分为有符号跟无符号两种,下一节我们会说到一些方法。

    2018-12-03
    4
  • GoghVin
    老师,您好,我有个问题想咨询下,我看了Breakpad的源码,发现在生成minidump的时候,其获取的是线程栈顶32K的内存区域(BreakPad注释(linux_dumper.cc:/LinuxDumper::GetStackInfo)
    // Get information about the stack, given the stack pointer. We don't try to
    // walk the stack since we might not have all the information needed to do
    // unwind. So we just grab, up to, 32k of stack.),
    请问这个理解是正确的吗?如果是正确的,那么只要运行时的栈空间大于32k,那么在服务端进行堆栈回溯的时候,就会有问题,为了验证这个猜测,我在您给的demo基础上进行了测试,代码如下:
    //==========Code 1===========
      int frame[1024];
        memset(frame, 0, sizeof(int)*1024);
        volatile int *a = (int *) (NULL);
        *a = 1;
    //==========Code 2===========
      int frame[40*1024];
        memset(frame, 0, sizeof(int)*40*1024);
        volatile int *a = (int *) (NULL);
        *a = 1;

    Code 1和Code2的堆栈是不一致的,Code1中可以看到函数的调用关系,而Code2中只能看到最后crash的函数,没有调用关系。

    作者回复: 对的,是这样的,你这个例子里的数组会放在栈里,占用空间

    2019-03-26
    2
  • 古月弓虽1993
    下载 depot_tools 工具后 fetch breakpad 老是失败,上网搜了不少方法,还是没有解决 fetch breakpad 失败的问题。后来自己想了想,fetch breakpad 实际上就是拉取 breakpad 的源码,既然通过 depot_tools 工具下载失败,直接从 github 上把 breakpad 源码 clone 下来不就好了。从github 上面直接clone 源码就好了(需要补充个缺失的文件)
    2019-01-13
    2
  • Seven
    交作业啦

    首次看到这篇文章后就进行了手动操作,无奈遇到了模拟器无法生产dmp文件,不过还好用真机可以生成成功,但是使用sample中的tools工具不能生成txt文件,后面倒是生成了,但生成的txt却是个空文件,低迷了一段时间,却又无可奈何,后来换用了windows,结果没想到难度系数无限增大。

    最近看了疑点解答的文章后,又重新产生了希望,开始动手实践,终于搞定了模拟器无法生产dmp文件的问题,继续使用Mac操作,总算成功了。

    第一步:
    运行sample,得到dmp文件,将文件导入到电脑中

    第二步:
    git下来Google的breakpad项目,使用./configure && make进行项目编译

    第三步:
    使用/breakpad/src/processor/microdump_stackwalk,对dmp文件进行处理,得到txt文件
    命令:microdump_stackwalk xxx.dmp >xxx.txt
    成果如下:
    Operating system: Android
                      0.0.0 Linux 4.4.23+ #1 SMP PREEMPT Mon Sep 17 22:10:21 CST 2018 aarch64
    CPU: arm64
         8 CPUs

    GPU: UNKNOWN

    Crash reason: SIGSEGV /SEGV_MAPERR
    Crash address: 0x0
    Process uptime: not available

    Thread 0 (crashed)
     0 libcrash-lib.so + 0x5dc // 利用这个地址
         x0 = 0x0000000000000000 x1 = 0x0000000000000001
         x2 = 0x0000000000000000 x3 = 0x0000007a494a3a00

    第四步:
    根据编译得到的信息:CPU: arm64,0x5dc
    根据这两个信息,使用NDK对应目录下的处理工具,我这里的信息使用的工具是:
    /android-ndk-r16b/toolchains/aarch64-linux-android-4.9/prebuilt/darwin-x86_64/bin/aarch64-linux-android-addr2line
    命令:/xxx/xxx/xxx-addr2line -f -C -e /xxx/Chapter01/sample/build/intermediates/transforms/mergeJniLibs/debug/0/lib/arm64-v8a/libcrash-lib.so
    解析得到的信息如下:
    Crash()
    /Users/qixuefeng/AndroidDemo/Chapter1/sample/src/main/cpp/crash.cpp:10
    2018-12-18
    2
  • 青松
    windows平台,直接用Android studio导入工程,开始出现apk的库里没有libbreakpad-core.so的问题。
    然后今天更新代码后可以了,看到提交记录加了arm64-v8a。
    代码里的minidump_stackwalk的版本是mac的,但是在Android Studio\bin\lldb\bin找到了minidump_stackwalk.exe,也可以解析出crashLog,格式和内容看起来都非常正常,但是再使用arm-linux-androideabi-addr2line来定位代码就始终显示?,无法成功。 怀疑是minidump_stackwalk的问题。看了评论区发现windows的用户都是用了虚拟机的linux才成功的。是minidump_stackwalk无法在windows平台使用么? 我已经在网上找了一圈,都没有找到如何在windows下编译minidump_stackwalk。望大佬帮忙解答下,谢谢!
    2018-12-07
    2
收起评论
99+
返回
顶部