如何定位分析缺陷原因分析,定位Android Native Crash

下次自动登录
现在的位置:
& 综合 & 正文
Android Native Crash调试方法
Native调试方法, 一个tombstome文件如下
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'sprd/sprdroid_base/hsdroid:2.3.5/MocorDroid2.3.5/W13.08_702:eng/test-keys'
pid: 151, tid: 23358
&&& /system/bin/mediaserver &&&
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 80c1e0c8
r0 00086b34
r3 80c1e0bc
r6 0005adc8
r8 80b09015
ip a39ad7ec
sp 41627e60
lr a3928d5d
pc a3928d64
9f9f9f9f9f9f9f9f
a1a1a1a1a1a1a1a1
a2a2a2a2a2a2a2a2
a2a2a2a2a2a2a2a2
d12 01e701e701e701e7
d13 01e701e701e701e7
d17 a5a5a5a5a5a5a5a5
d18 a5a5a5a5a5a5a5a5
d19 a5a5a5a5a5a5a5a5
d20 a5a5a5a5a5a5a5a5
d21 a4a4a4a4a4a4a4a4
d22 a4a4a4a4a4a4a4a4
d23 a2a2a2a2a2a2a2a2
d24 016d016d016d016d
d25 016d016d016d016d
d26 7a7a7a7a7a7a7a7a
d27 7a7a7a7a7a7a7a7a
d28 00f200f200f200f2
d29 00f200f200f200f2
d30 00f400f400f400f4
d31 00f400f400f400f4
pc 00028d64
/system/lib/libopencore_common.so
pc 00028f8c
/system/lib/libopencore_common.so
/system/lib/libopencore_common.so
pc 00008f66
/system/lib/libomx_sharedlibrary.so
/system/lib/libomx_sharedlibrary.so
pc 00011d4c
/system/lib/libc.so
/system/lib/libc.so
code around pc:
ae06 5ca0f501 4000f8dc
a4eb01 e9daf7f8 b39804
a068da f1b0e005 bf063fff 684c9906
a62400 ffa8f00b d03d2c00
a21 d05d034
code around lr:
a289d04 68d9682b e19e06
aca0f501 4000f8dc daf7f8
a3928d5c bda f1b0e005
a3928d6c bf063fff 684c0 ffa8f00b
a3928d7c d03d2c00 21
/system/lib/libomx_sharedlibrary.so
/system/lib/libc.so
#00 066844
/system/lib/libopencore_common.so
/system/lib/libopencore_common.so
#01 000000
/system/lib/libomx_sharedlibrary.so
/system/lib/libomx_sharedlibrary.so
/system/lib/libopencore_common.so
#02 405adc8
/system/lib/libomx_sharedlibrary.so
#03 4627f00
/system/lib/libomx_sharedlibrary.so
#04 4083c38
/system/lib/libc.so
#05 4627f00
/system/lib/libc.so
#06 627f00
这个可以使用stacktrace工具来查看
./stacktrace --symbols-dir=符号表目录
tombstome_file
另外还可以用core dump进行调试
core dump需要一下几个步骤,对android,可以在开机的时候在init.rc里去执行
在init.rc里加上
setrlimit 4 -1 -1
write /proc/sys/kernel/core_pattern "/local/log/core-%e-%p-%t"
(1)使用ulimit命令开启coredump功能。
(2)修改coredump文件生成位置与名称
(3)gdb的使用方法
(1)adb连接手机,开启coredump
# ulimit -a
time(seconds)
file(blocks)
data(kbytes)
stack(kbytes)
coredump(blocks)
//这里coredump是开启的,大小为不限制,可以用ulimit -c unlimited修改成不限制大小
memory(kbytes)
locked memory(kbytes) 64
process(processes)
nofiles(descriptors) 1024
(2)配置coredump文件生成位置与名称
#echo "1" & /proc/sys/kernel/core_uses_pid
//允许文件名后加pid
#echo "/local/log/core-%e-%p" & /proc/sys/kernel/core_pattern
#echo 1 & /proc/sys/fs/suid_dumpable
把dump文件存放目录改到local/log下。
(3)示例程序
#include &stdio.h&
static void sub(void);
int main(void)
static void sub(void)
int *p = NULL;
printf("%d",*p);
然后编译,android会生成两种版本的文件,一种是带符号信息的,
out/target/product/generic/symbols/system/bin/foo
另一种是不带符号信息的(即strip过的)
out/target/product/generic/system/bin/foo
不带符号信息的会做到system.img中去,带符号信息的我们需要保存住,以备后续调试用。
上面第二个log信息就是此程序运行的结果。
我们把generic/system/bin/foo文件拷贝到手机中,比如local目录下,修改权限(chmod 777 foo),执行,结果如下。
[1] + Stopped (signal)
Segmentation fault (core dumped) ./foo
然后可以看到/local/log目录下多了一个coredump文件, 进程id位1673
core-foo-1673
将core-foo-1673与generic/symbols/system/bin/foo(这个必须是带符号的)拷贝到相同目录下
运行gdb进行调试,注意这里要运行的gdb是android自带的,我这里的名称叫arm-eabi-gdb
$arm-eabi-gdb ./foo
GNU gdb 6.6
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
The GDB was configured as "--host=i686-unknown-linux-gnu --target=arm-elf-linux"...
输入core-file文件,回车
(gdb) core-file core-foo-1672
warning: core file may not match specified executable file.
Error while mapping shared library sections:
/system/bin/linker: No such file or directory.
Error while mapping shared library sections:
libc.so: Success.
Error while mapping shared library sections:
libstdc++.so: Success.
Error while mapping shared library sections:
libm.so: Success.
Symbol file not found for /system/bin/linker
Symbol file not found for libc.so
Symbol file not found for libstdc++.so
Symbol file not found for libm.so
warning: Unable to find dynamic linker breakpoint function.
GDB will be unable to debug shared library initializers
and track explicitly loaded dynamic code.
Core was generated by `./foo'.
Program terminated with signal 11, Segmentation fault.
#0 0x0000836a in main () at external/coredump/foo.c:15 ==》看到这种信息知道该知道哪出错了把
printf("%d",*p)
如果函数调用关系比较复杂,可试试bt(backtrace)指令
附录:在PC机上做的实验
linux 上core dump及应用
【1】core dump 概念
http://en.wikipedia.org.nyud.net:8080/wiki/Core_dump
【2】示例:在Linux下产生并调试core文件
参考http://www.zedware.org/code/code-coredump.html
$ ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) 4
max memory size (kbytes, -m) unlimited
open files (-n) 2048
pipe size (512 bytes, -p) 8
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 7168
virtual memory (kbytes, -v) unlimited
写个简单的程序,看看core文件是不是会被产生。创建foo.c,使内容如下。
$ more foo.c
#include &stdio.h&
static void sub(void);
int main(void)
static void sub(void)
int *p = NULL;
/* derefernce a null pointer, expect core dump. */
printf("%d", *p);
$ gcc -Wall -g foo.c
【-Wall :[Warning all] 显示所有常用的编译警告信息。 -g选项,将调试信息加入到目标文件或可执行文件中。】
Segmentation fault
【所谓的Segmentation Fault(段错误)就是指访问的内存超出了系统所给这个程序的内存空间】
$ ls -l core*
ls: core*: No such file or directory
没有找到core文件,我们改改ulimit的设置,让它产生,1024是随便取的,也可以使用ulimit -c unlimited不限制大小。
$ ulimit -c 1024
$ ulimit -a
core file size (blocks, -c) 1024
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
max locked memory (kbytes, -l) 4
max memory size (kbytes, -m) unlimited
open files (-n) 2048
pipe size (512 bytes, -p) 8
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 7168
virtual memory (kbytes, -v) unlimited
Segmentation fault (core dumped)
$ ls -l core*
-rw------- 1 uniware uniware 53248 Jun 30 17:10 core.9128 【此处也可能是名称为core的文件】
注意看上述的输出信息,多了个(core dumped)。确实产生了一个core文件,9128是该进程的PID。我们用GDB来看看这个core。
$ gdb --core=core.9128
GNU gdb Asianux (6.0post-0..1AX)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This was configured as "i386-asianux-linux-gnu".
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
#0 0x in ?? ()
#0 0x in ?? ()
#1 0xbfffd8f8 in ?? ()
#2 0x0804839e in ?? ()
#3 0xb74cc6b3 in ?? ()
#4 0x in ?? ()
此时用bt看不到backtrace,也就是调用堆栈,原来GDB还不知道符号信息在哪里。我们告诉它一下:
(gdb) file ./a.out
Reading symbols from ./a.out...done.
Using host libthread_db library "/lib/tls/libthread_db.so.1".
#0 0x in sub () at foo.c:17
#1 0x in main () at foo.c:8
此时backtrace出来了。
(此处是“L”的小写,不是数字“1”)
static void sub(void)
int *p = NULL;
/* derefernce a null pointer, expect core dump. */
printf("%d", *p);
参考http://blog.csdn.net/shaovey/archive//2744487.aspx
在程序不寻常退出时,内核会在当前工作目录下生成一个core文件(是一个内存映像,同时加上调试信息)。使用gdb来查看core文件,可以指示出导致程序出错的代码所在文件和行数。
1.core文件的生成开关和大小限制
1)使用ulimit -c命令可查看core文件的生成开关。若结果为0,则表示关闭了此功能,不会生成core文件。
2)使用ulimit -c filesize命令,可以限制core文件的大小(filesize的单位为kbyte)。如果生成的信息超过此大小,将会被裁剪,最终生成一个不完整的core文件。在调试此core文件的时候,gdb会提示错误。若ulimit -c unlimited,则表示core文件的大小不受限制。ulimit -c 0关闭该功能。
PS: ulimit使用方法见/developerworks/cn/linux/l-cn-ulimit/
2.core文件的名称和生成路径
core文件生成路径:输入可执行文件运行命令的同一路径下。
若系统生成的core文件不带其它任何扩展名称,则全部命名为core。新的core文件生成将覆盖原来的core文件。
1)/proc/sys/kernel/core_uses_pid可以控制core文件的文件名中是否添加pid作为扩展。文件内容为1,表示添加pid作为扩展名,生成的core文件格式为core.xxxx;为0则表示生成的core文件同一命名为core。
可通过以下命令修改此文件:
echo "1" & /proc/sys/kernel/core_uses_pid
2)proc/sys/kernel/core_pattern可以控制core文件保存位置和文件名格式。
可通过以下命令修改此文件:
echo "/corefile/core-%e-%p-%t" & core_pattern,可以将core文件统一生成到/corefile目录下,产生的文件名为core-命令名-pid-时间戳
以下是参数列表:
%p - insert pid into filename 添加pid
%u - insert current uid into filename 添加当前uid
%g - insert current gid into filename 添加当前gid
%s - insert signal that caused the coredump into the filename 添加导致产生core的信号
%t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间
%h - insert hostname where the coredump happened into filename 添加主机名
%e - insert coredumping executable name into filename 添加命令名
3.core文件的查看
core文件需要使用gdb来查看。
gdb ./a.out
core-file core.xxxx
使用bt命令即可看到程序出错的地方。
以下两种命令方式具有相同的效果,但是在有些环境下不生效,所以推荐使用上面的命令。
1)gdb -core=core.xxxx
file ./a.out
2)gdb -c core.xxxx
file ./a.out
&&&&推荐文章:
【上篇】【下篇】Android Crash之Java Crash分析 - CSDN博客
Android Crash之Java Crash分析
小巫最近由于工作原因面临技术转型,从一个App开发者转变为SDK开发者,这两者的区别是非常明显的,从用户角度来讲,app开发主要面向普通的用户需求,然而SDK开发面向的却是开发人员;从技术角度来讲,app开发更多的只是UI层面、基于数据流的技术实现,而SDK开发可能就要涉及更多复杂的需求、更多底层相关的技术实现。前面我在公众号分享了一篇文章:,大家有兴趣可以看看。本系列博文主要是想跟大家分享一下在Android平台中如何进行Crash分析并解决问题并告诉大家如何通过bugly进行崩溃捕获快速定位问题。
什么是Crash?
想必这个只要从事过编程工作的同学一定知道是什么?这里我们进行一些概念上的普及:
Crash就是由于代码异常而导致App非正常退出现象,也就是我们常说的『崩溃』
Android中有哪些类型Crash
通常情况下会有以下两种类型Crash:
Java Crash
Native Crash
本篇先探讨Java Crash,Native Crash我们会在下一篇重点讨论。
Java Crash在Android上的特点
这类错误一般是由Java层代码触发的
2. 一般情况下程序出错时会弹出提示框,JVM虚拟机退出
3. 一般的Crash工具都能够捕获,系统也提供了API
我们可以看到,button是没有被实例化的,我们调用它的方法就会让程序崩溃,如下图所示:
通过Crash堆栈信息定位问题
上面就是一个很简单的Crash啦,相信很多同学在开发过程中一定遇到过这种情况,万恶的空指针啊,啊,啊。我们来看看logcat给我们输出的堆栈信息:
通过logcat查看Error级别日志,就可以完整看到打印出来的堆栈信息,我们找到『Caused by』信息:
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
at com.devilwwj.androidcrashdemo.MainActivity.onCreate(MainActivity.java:18)
这个日志很明确告诉我们,这个crash是由于空指针异常引起的,尝试通过一个空对象引用去调用虚方法setOnClickListener在com.devilwwj.androidcreashdemo.MainActivity.onCreate方法里,在MainActivity.java文件的18行的位置。
上一节我们很轻松定位到问题,我们升华一下把它解决掉,我们找到18行,修改代码如下:
这个时候程序就正常运行了,是不是很简单啊,但这种情况是自己在开发中调试运行时可以通过logcat来定位问题,但如果产品上线之后你怎么办,用户都是小白哦,可不会给你提供错误日志,这个就是本篇文章要讲的重点,如果要让我们自己记录错误日志,怎么做?
通过UncaughtExceptionHandler来记录dump异常日志
package com.devilwwj.
* com.devilwwj.androidcrashdemo
* Created by devilwwj on 16/5/27.
import android.content.C
import android.content.pm.PackageI
import android.content.pm.PackageM
import android.content.pm.PackageManager.NameNotFoundE
import android.os.B
import android.os.E
import android.os.P
import android.util.L
import java.io.BufferedW
import java.io.F
import java.io.FileW
import java.io.IOE
import java.io.PrintW
import java.lang.Thread.UncaughtExceptionH
import java.text.SimpleDateF
import java.util.D
public class CrashHandler implements UncaughtExceptionHandler {
private static final String TAG = "CrashHandler";
private static final boolean DEBUG = true;
private static final String PATH = Environment
.getExternalStorageDirectory() + "/CrashDemo/log/";
private static final String FILE_NAME = "crash";
private static final String FILE_NAME_SUFFIX = ".trace";
private static final String ABOLUTE_PATH = PATH + FILE_NAME + FILE_NAME_SUFFIX;
private String deviceT
private static CrashHandler sInstance = new CrashHandler();
private UncaughtExceptionHandler mDefaultCrashH
private Context mC
private CrashHandler() {
public static CrashHandler getInstance() {
public void init(Context context) {
mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
mContext = context.getApplicationContext();
* 这个是最关键的函数,当程序中有未被捕获的异常,系统将会自动调用#uncaughtException方法
* thread为出现未捕获异常的线程,ex为未捕获的异常,有了这个ex,我们就可以得到异常信息。
public void uncaughtException(Thread thread, Throwable ex) {
dumpExceptionToSDCard(ex);
} catch (IOException e) {
e.printStackTrace();
ex.printStackTrace();
if (mDefaultCrashHandler != null) {
mDefaultCrashHandler.uncaughtException(thread, ex);
Process.killProcess(Process.myPid());
private File dumpExceptionToSDCard(Throwable ex) throws IOException {
if (!Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
if (DEBUG) {
Log.w(TAG, "sdcard unmounted,skip dump exception");
return null;
File dir = new File(PATH);
if (!dir.exists()) {
dir.mkdirs();
long current = System.currentTimeMillis();
String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.format(new Date(current));
File file = new File(PATH + FILE_NAME + FILE_NAME_SUFFIX);
if (!file.exists()) {
file.createNewFile();
PrintWriter pw = new PrintWriter(new BufferedWriter(
new FileWriter(file, true)));
pw.println(time);
dumpPhoneInfo(pw);
pw.println();
ex.printStackTrace(pw);
pw.println("---------------------------------分割线----------------------------------");
pw.println();
pw.close();
} catch (Exception e) {
Log.e(TAG, "dump crash info failed");
private void dumpPhoneInfo(PrintWriter pw) throws NameNotFoundException {
PackageManager pm = mContext.getPackageManager();
PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(),
PackageManager.GET_ACTIVITIES);
pw.print("App Version: ");
pw.print(pi.versionName);
pw.print('_');
pw.println(pi.versionCode);
pw.print("OS Version: ");
pw.print(Build.VERSION.RELEASE);
pw.print("_");
pw.println(Build.VERSION.SDK_INT);
pw.print("Vendor: ");
pw.println(Build.MANUFACTURER);
pw.print("Model: ");
pw.println(Build.MODEL);
pw.print("CPU ABI: ");
pw.println(Build.CPU_ABI);
* 提供方法上传异常信息到服务器
private void uploadExceptionToServer(File log) {
上面是核心代码,可以直接拿去用,可以在Application类中进行初始化:
如果程序发生异常,就会将异常写入到指定文件中,日志的格式你可以自己指定,如果有上传服务器记录crash的需求就可以通过POST方式将文件上传,具体实现方式跟后台沟通即可。
最终的效果如下:
当然上面只适用于Java Crash捕获,如果想更专业捕获到异常并更高效分析程序问题,可以尝试使用专业的第三方SDK来实现,这里推荐『』,可以参考一下笔者前面发表的文章『』。
关于Java Crash的分析已经介绍完了,相对还是比较简单,通过简单的方式就能够捕获到异常,但别忘了,Android最头痛的不是这种异常,而是Native层的异常,有时候就算能让你拿到堆栈信息你也不一定会解决问题,比如你使用了第三方的so库,如果发生崩溃了,你也会崩溃的。想了解更多内容,敬请关注下一篇『Android Crash之Native Crash分享』。
本文已收录于以下专栏:
相关文章推荐
Android平台程序崩溃大家都应该遇到过,force close和ANR应该是大家遇到较多的。
这里把Android平台程序崩溃的各种类型做一个简述和原因列举。
1.ANR(可见ANR)...
转载请注明来源:http://blog.csdn.net/singwhatiwanna/article/details/
大家都知道,android应用不可避免的会发生crash...
大家都知道,现在安装Android系统的手机版本和设备千差万别,在模拟器上运行良好的程序安装到某款手机上说不定就出现崩溃的现象,开发者个人不可能购买所有设备逐个调试,所以在程序发布出去之后,如果出现了...
我们开发Android应用的时候,当出现Crash的时候,系统弹出一个警告框,如下图一,有些手机会黑屏几秒钟然后还伴随着振动,作为我们开发人员,是很讨厌这样子的Crash,因为这意味着我们又要改bug...
结合拜读包建强前辈著作的《App研发录》,与自己开发过程中遇到的问题,继续上篇对android开发经常碰到的crash探讨。上篇已经对空指针、数组越界、数据类型转换、fragment引用资源出错、di...
在实际项目开发中,会出现很多的异常直接导致程序crash掉,在开发中我们可以通过logcat查看错误日志,Debug出现的异常,让程序安全的运行,但是在开发中有些异常隐藏的比较深,直到项目发布后,由于...
本文介绍了如何在 Android 手机发生 Crash 时进行 Log 分析的方法,
它可以帮助测试人员快速定位 Android 手机 Crash 发生的原因,同时给研发人员提供有效修改 Bug 的...
Crash、FC、froce close
应用进程崩溃。强制关闭,android App 因为代码异常导致奔溃。
表现形式主要有两种
1.      Java 代码引起,弹出错误的提...
前言上一篇给大家介绍了Android Crash中的Java Crash分析,我们可以知道Java Crash一般会弹出提示框告诉我们程序崩溃了,通常使用Crash工具都能够捕获到;本篇博客来谈谈如何...
1.什么是Crash?
Crash最通俗直观的感受就是App软件出现崩溃导致的闪退等现象,在Android原生态下会出现一个App Force Close的Dialog,但是对于用户体验相当不好。C...
他的最新文章
讲师:吴岸城
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。下次自动登录
现在的位置:
& 综合 & 正文
Android Tombstone/Crash的log分析和定位
有一句话叫做常在河边走,哪有不湿鞋。我们这些研究和开发Android的工程师正应了这句话,相必大家在调试的时候经常会遇到这么个东西吧
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'XXXXXXXXX'pid: 1658, tid: 13086
&&& system_server &&&
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 64696f7e
r2 ad12d1e8
r3 7373654d
r4 64696f72
r7 40d14008
r8 4b857b88
r9 4685adb4
fp 4b857ed8
sp 4b857b50
lr afd11108
pc ad115ebc
00e81fe04b1b64d8
/system/lib/libc.so
pc 0003724c
/system/lib/libxvi020.so
pc 0000ce02
/system/lib/libxvi020.so
/system/lib/libxvi020.so
pc 00010cce
/system/lib/libxvi020.so
/system/lib/libwimax_jni.so
pc 00011e74
/system/lib/libdvm.so
pc 0004354a
/system/lib/libdvm.so
/system/lib/libdvm.so
/system/lib/libdvm.so
/system/lib/libdvm.so
pc 00059c24
/system/lib/libdvm.so
pc 00059e3c
/system/lib/libdvm.so
pc 0004e19e
/system/lib/libdvm.so
pc 00011b94
/system/lib/libc.so
pc 0001173c
/system/lib/libc.so
code around pc:
ad115e9c 4620eddc bf00bd70 01734e
ad115eac c4c0a f7f4edc8
ad115ebc 42ab68e3 68a0d103 f7fedd2
ad115ecc d1f52c00
edbef7f4 bf00bd70
ad115edc b51f
code around lr:
afd110e8 ea404
afd110f8 ea01 ebffed92
afd10 a000001 ea000009
afd11118 ebfffe50 e1a006 ebffed92
afd105 ea000
/system/lib/libnativehelper.so
初一看到直接崩溃,我的个妈,这么一大坨,啥玩意啊,完全搞不懂,没有头绪撒。这NND Android出了问题,冒出这么大堆的地址,搞毛呢。
其实, 我可以很负责任的告诉你,兄弟这么多其实我也看不懂,在我眼里除了红色和蓝色的地方,其他全是废话。因为除了这两个地方意外,其他的我确实看不懂,一堆线性地址,外加寄存器,跟火星文一样。
算了,废话不多少,直接分析:
1 红色的地方,是让我们确认问题到底发生在那个线程中,是主线程还是子线程,这个的判断依据是:如果PID和TID相同,恭喜你问题出在父亲这边,看样子问题还比较好办。如果PID和TID不相同,那么您悲剧了,问题出在子线程中。根据我的经验,100的tombstone中,问题出现在父线程的概率,我还从来没发现,尤其是什么system_server, zygote这些,基本都是儿子的问题。唉,谁叫父亲英雄,儿狗熊呢。。。
2 确认了问题的基本点,下面就是开始看蓝色的部分了。
这个蓝色不分是从#00--&#XX 表面上看是从上往下的增长,其实坑爹啊,它所显示的程序的执行流程,恰恰是从下往上的也就是实际的执行顺序是#XX--&#00。
所以一开始我们的目的是分析第一个出现问题的动态连接库
pc 0001173c
/system/lib/libc.so
a 首先按图索骥,找到你的目标,libc.so这个一般会在你编译完的目标目录下,也就是out/target/product/your_pro/system/lib这个目录下。
b 一般你如果用的是还像样的linux系统,会有个地址解析的命令addr2line,负责解析动态连接库的(如果你是悲剧,没有这个命令,那好吧, google早就预料到会有象你这样的悲剧人,他们在prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/arm-eabi-addr2line,给您准备了个,咋就用这个吧,功能一样,没啥区别)
addr2line -e -f libc.so 0001173c
红色是你的目标库,绿色是你出问题的地址,看看#15这行
结果出现:??pthread_create
恩,好了问题应该出在这个函数中,认为大功告成了?我,呸,还早呢。这个只是告诉你函数入口,至于具体执行到这个函数的哪个地方挂了,还得再看。
c 找到了是哪个部分出了问题,下面就是开启显微镜,看看谁搞的东东。
使用objdump -S -D libc.so & deassmble_libc.txt 反汇编下你的动态连接库文件,并且将它写入一个文件中。
打开这个反汇编过后的重定向文件,在查询的时候输入1173c这个偏移地址,你会看到在茫茫人海中
&pthread_create&:
{r4, r5, r6, r7, r8, r9, sl, fp, lr}
sp, sp, #28 0x1c
r4, #1 0x1
r5, [pc, #540] 118c0 &pthread_create+0x23c&
r0, [sp, #12]
37f80 &strncmp+0x20&
r2, [pc, #532] 118c4 &pthread_create+0x240&
r0, #60 ; 0x3c
r3, pc, r5
r3, [r3, r2]
ip, [sp, #16]
37fc0 &strncmp+0x60&
c7f0 &__pthread_clone&--&就是他了,对你成功了。
这个是ARM汇编,需要你翻译成对应的C函数去看,这里我就不做解释了,照着前面的步骤,
对上面中#15--&#00 一共16行慢慢去找,直到找到#00行的问题函数,其实,最后一个#00行的是最重要的(前面不找也行,但是可以多给你提供问题信息,和流程),因为他是第一目击者,也是Crash前的第一现场。所以找到这个函数很重要,假设我们最后经过万里长针发现#00的出错的地方是pXX-&member挂了(MD,我经常遇到这种问题)。
那么你可以怀疑两个地方:
1 您的指针是空指针,但是现实与理想总是十万八千里,多数情况下很少出现,而且你分析代码后,也会对自己说怎么可能。绝大多数情况下,从我的经验来讲,很少会有空指针这种低级错误,但是不排除哪个2货出现了这么个问题。如果是这个问题,那么恭喜你,你很幸运。
2 还有就是怀疑越界和内存地址被挤占。就拿我以前的经验,指针不是空,但是根据汇编码看,是访问成员变量挂了,这个地址肯定是被占用了。
针对第2种比较恶心的情况,就需要你看整个log的流程了,需要你看下主要的mainlog关于出现crash前的动作,看看是哪个孙子占用的,以最近原则为先,从下往上看,唉,说句实在话,李白的一句话可以形容整个过程:"蜀道难,难于上青天啊"。工作量大,而且要细致。我也没什么办法。。。
还有一种情况,就是内存不够,导致了您的地址被挤占了,出现low memory, no more ...这样的语句,以及大量出现GC_FOR_MALLOC关于GC的东西(如果是少量的,可以忽略,大量的话),呵呵表明你的某个进程在吞噬你的内存,存在内存泄漏。坑爹啊,这个问题,是最难查的,需要你花大量时间,去看内存的变化。一般看内存的情况是
cat /proc/meminfo
空闲内存=buffer+cache+free这三个字段,Active字段是已经使用的内存,Total不用说,是总的物理内存。(记住 free不高,并不代表你的内存空闲不高,海水不可斗量,需要看全了3个字段的总和才是空闲内存)
如果你想具体跟踪每个进程的内存使用情况,还是在/proc下面,对应了N多的数字文件,那个其实是PID号,进去后cat status可以看到
VMRSS XXXKB就是你当前进程的使用内存量,此外还有一些其他的内存数据,包括页啊等等。。。里面还有很多有用的数据,如果你想跟踪所有的进程的内存情况,推介大家可以看看linux ps命令的源码,看看人家是怎么在/proc下遍历进程,并且提取属性值的。
写个daemon,跟踪一段时间,记录下各进程内存的变化,然后就是通宵的分析。。。。
总之,这类问题,很难定位,也很难解决,需要花时间,精力去分析。但是如果你解了,那么相信所有人对你会刮目相看的。包括你的老板,量变引起质变,请记住。
我还在纠结中啊...分析ing
最后再说几句
#12 476e5eb8
/system/lib/libdvm.so
#13 476e5ed8
/system/lib/libdvm.so
/system/lib/libc.so
#14 476e5ef0
/system/lib/libc.so
#15 476e5f00
红色的部分是基地址+偏移地址
比如afd +11740 这个afd你可以从prelink-linux-arm.map找到每个.so的基地址(比如 libc.so
0xAFD00000 # [~2M])11740可以从反汇编的文件中找到对应点,但是我不知道这些有什么用。
希望这偏小文章能帮助到大家,大家共同进步,有好的方法也欢迎您一起分享。谢谢!
下面是一个老外的摘录早期存于google论坛的内存分析文章(现在没了),我是在他基础上,又加了一些分析和经验之谈,希望上帝保佑让我早点定位到问题。
&&&&推荐文章:
【上篇】【下篇】}

我要回帖

更多关于 人群定位分析 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信