一、获取Crash Log的方式

在iOS开发过程,当应用已经打包,iPhone设备通过ipa的包安装应用后,在使用过程发现crash,那么如何获取crash日志呢,现提供如下四种获取crash日志的方式:

1、打开iPhone设备的设置里面的隐私中的“诊断与用量”,然后如果app崩溃了,设备会弹出提示框,用户确认之后,crash log会自动发送到苹果后台,然后用开发者账号登陆上去,可以拿到crash log。

2、将设备链接到mac或者windows上,同步到iTunes后再从电脑的目录下获取crash log:

Mac OS X:~/Library/Logs/CrashReporter/MobileDevice

Windows XP:C:\Documents and Settings\Application Data\Apple computer\Logs\CrashReporter

Windows 7/Vista: C:\Users\计算机登录名\AppData\Roaming\Apple Computer\Logs\CrashReporter\MobileDevice

3、可以通过itools工具获取crash log,打开itools,连接iPhone设备,按照下图提示,获取crash log

4、通过xcode获取crash log,打开Xcode,连接iPhone设备,打开window下的device,可以看到你连接的设备,可以看到如下界面,点击view device logs,可以看到所有的日志,选中日志,点击右键可以到处日志

二、解析Crash Logs --- 符号化crash文件(Symbolicating crash logs)

crash logs:

 Last Exception Backtrace:
0 CoreFoundation 0x30acaf46 exceptionPreprocess + 126
1 libobjc.A.dylib 0x3af0b6aa objc_exception_throw + 34
2 CoreFoundation 0x30a0152e -[__NSArrayM objectAtIndex:] + 226
3 appName 0x000f462a 0x4000 + 984618
4 appName 0x00352aee 0x4000 + 3468014

18 appName 0x00009404 0x4000 + 21508

大家一眼就能看到:

2 CoreFoundation 0x30a0152e -[__NSArrayM objectAtIndex:] + 226

这一行有问题。

但是,第3行和第4行的:

3 appName 0x000f462a 0x4000 + 984618
4 appName 0x00352aee 0x4000 + 3468014

并没有指出到底是app的那个模块导致的问题,如何排查呢?

有如下3种方法

方法1 使用XCode

这种方法可能是最容易的方法了。

需要使用Xcode符号化 crash log,你需要下面所列的3个文件:

  1. crash报告(.crash文件)
  2. 符号文件 (.dsymb文件)
  3. 应用程序文件 (appName.app文件,把IPA文件后缀改为zip,然后解压,Payload目录下的appName.app文件), 这里的appName是你的应用程序的名称。

把这3个文件放到同一个目录下,打开Xcode的Window菜单下的organizer,然后点击Devices tab,然后选中左边的Device Logs。

然后把.crash文件拖到Device Logs或者选择下面的import导入.crash文件。

这样你就可以看到crash的详细log了。 如下图:

方法2 使用命令行工具symbolicatecrash

有时候Xcode不能够很好的符号化crash文件。我们这里介绍如何通过symbolicatecrash来手动符号化crash log。

在处理之前,请依然将“.app“, “.dSYM”和 ".crash"文件放到同一个目录下。现在打开终端(Terminal)然后输入如下的命令:

export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer

然后输入命令:

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/PrivateFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash appName.crash appName.app > appName.log

现在,符号化的crash log就保存在appName.log中了。

方法3 使用命令行工具atos

如果你有多个“.ipa”文件,多个".dSYMB"文件,你并不太确定到底“dSYMB”文件对应哪个".ipa"文件,那么,这个方法就非常适合你。

特别当你的应用发布到多个渠道的时候,你需要对不同渠道的crash文件,写一个自动化的分析脚本的时候,这个方法就极其有用。

三、UUID

1.UUID

每一个可执行程序都有一个build UUID来唯一标识。Crash日志包含发生crash的这个应用(app)的 build UUID以及crash发生的时候,应用加载的所有库文件的[build UUID]。

2.crash文件的UUID

可以用:

    grep "appName armv" *crash

或者

    grep --after-context=2 "Binary Images:" *crash

可以得到类似如下的结果:

    appName.crash-0x4000 - 0x9e7fff appName armv7 <8bdeaf1a0b233ac199728c2a0ebb4165> /var/mobile/Applications/A0F8AB29-35D1-4E6E-84E2-954DE7D21CA1/appName.crash.app/appName

(请注意这里的0x4000,是模块的加载地址,后面用atos的时候会用到)

3.找app的UUID

可以使用如下指令

xcrun dwarfdump -–uuid <AppName.app/ExecutableName>

比如:

xcrun dwarfdump --uuid appName.app/appName 

结果如下:

    UUID: 8BDEAF1A-0B23-3AC1-9972-8C2A0EBB4165 (armv7) appName.app/appName
UUID: 5EA16BAC-BB52-3519-B218-342455A52E11 (armv7s) appName.app/appName

这个app有2个UUID,表明它是一个fat binnary。

它能利用最新硬件的特性,又能兼容老版本的设备。

对比上面crash文件和app文件的UUID,发现它们是匹配的

8BDEAF1A-0B23-3AC1-9972-8C2A0EBB4165 

用atos命令来符号化某个特定模块加载地址

atos [-o AppName.app/AppName] [-l loadAddress] [-arch architecture] 

下面3种都可以:

    xcrun atos -o appName.app.dSYM/Contents/Resources/DWARF/appName -l 0x4000 -arch armv7
xcrun atos -o appName.app.dSYM/Contents/Resources/DWARF/appName -arch armv7
xcrun atos -o appName.app/appName -arch armv7
(注:这3行选任意一行执行都可以达到目的,其中0x4000是模块的加载地址,从上面的章节可以找到如何得到这个地址。)

crash文件中有如下两行,

    3 appName 0x000f462a 0x4000 + 984618
4 appName **0x00352aee** 0x4000 + 3468014

在执行了上面的:

xcrun atos -o appName.app.dSYM/Contents/Resources/DWARF/appName -l 0x4000 -arch armv7

之后,输入如下地址:

0x00352aee 

(crash文件中的第4行:4 appName **0x00352aee** 0x4000 + 3468014)

可以得到结果:

    -[UIScrollView(UITouch) touchesEnded:withEvent:] (in appName) (UIScrollView+UITouch.h:26)

这样就找到了应用种到底是哪个模块导致的crash问题。

四、常见的Crash类型

1、Watchdog timeout

Exception Code:0x8badf00d, 不太直观,可以读成“eat bad food”,意思是don‘t block main thread

紧接着下面会有一段描述:

Application Specific Information:

com.xxx.yyy   failed to resume in time

对于此类Crash,我们应该去审视自己App初始化时做的事情是否正确,是否在主线程请求了网络,或者其他耗时的事情卡住了正常初始化流程。

通常系统允许一个App从启动到可以相应用户事件的时间最多为5S,如果超过了5S,App就会被系统终止掉。在Launch,resume,suspend,quit时都会有相应的时间要求。在Highlight Thread里面我们可以看到被终止时调用到的位置,xxxAppDelegate加上行号。

PS. 在连接Xcode调试时为了便于调试,系统会暂时禁用掉Watchdog,所以此类问题的发现需要使用正常的启动模式。

2、User force-quit

Exception Codes: 0xdeadfa11, deadfall

这个强制退出跟我们平时所说的kill掉后台任务操作还不太一样,通常在程序bug造成系统无法响应时可以采用长按电源键,当屏幕出现关机确认画面时按下Home键即可关闭当前程序。

3、Low Memory termination

跟一般的Crash结构不太一样,通常有Free pages,Wired Pages,Purgeable pages,largest process 组成,同事会列出当前时刻系统运行所有进程的信息。

关于Memory warning可以参看我之前写的一篇文章IOS 内存警告 Memory warning level。

App在运行过程中,系统内存紧张时通常会先发警告,同时把后台挂起的程序终止掉,最终如果还是内存不够的话就会终止掉当前前台的进程。

当接受到内存警告的事后,我们应该释放尽可能多的内存,Crash其实也可以看做是对App的一种保护。

4、Crash due to bugs

因为程序bug导致的Crash通常千奇百怪,很难一概而论。大部分情况通过Crash日志就可以定位出问题,当然也不排除部分疑难杂症看半天都不值问题出在哪儿。这个就只能看功底了,一点点找,总是能发现蛛丝马迹。是在看不出来时还可以求助于Google大神,总有人遇到和你一样的Bug

五、常见的Exception Type

1. EXC_BAD_ACCESS

此类型的Excpetion是我们最长碰到的Crash,通常用于访问了不改访问的内存导致。一般EXC_BAD_ACCESS后面的"()"还会带有补充信息。

SIGSEGV: 通常由于重复释放对象导致,这种类型在切换了ARC以后应该已经很少见到了。

SIGABRT: 收到Abort信号退出,通常Foundation库中的容器为了保护状态正常会做一些检测,例如插入nil到数组中等会遇到此类错误。

SEGV:(Segmentation Violation),代表无效内存地址,比如空指针,未初始化指针,栈溢出等;

SIGBUS:总线错误,与 SIGSEGV 不同的是,SIGSEGV 访问的是无效地址,而 SIGBUS 访问的是有效地址,但总线访问异常(如地址对齐问题)

SIGILL:尝试执行非法的指令,可能不被识别或者没有权限

2. EXC_BAD_INSTRUCTION

此类异常通常由于线程执行非法指令导致

3. EXC_ARITHMETIC

除零错误会抛出此类异常

六、我在“牛牛好管家”项目中遇到的Crash Log做以下分析

项目在模拟器上一直没有问题,可是到真机上突然发生了Crash,瞬间整个人都感觉不好了。导出了机子上的Crash报告,咋一看天书一般,经过在http://stackoverflow.com上面查找终于搞明白了原因。先附上Crash报告:

// 1: Process Information
Incident Identifier: CCBEE2BC-E2FB-4E43-83D5-FBD6B87F2ADE
CrashReporter Key: 703cffef5d700f1eaa0d3921fb8ef142d4780cf9
Hardware Model: iPhone8,1
Process: NiuNiu [5639]
Path: /private/var/mobile/Containers/Bundle/Application/A37341B1-FC88-4E49-A102-017A7AE5218C/NiuNiu.app/NiuNiu
Identifier: com.sdbean.NiuNiuManagers
Version: 2.9.1 (1.3)
Code Type: ARM-64 (Native)
Parent Process: launchd [1] // 2: Basic Information
Date/Time: 2016-03-21 08:30:02.02 +0800
Launch Time: 2016-03-19 07:54:25.25 +0800
OS Version: iOS 9.2.1 (13D15)
Report Version: 105 // 3: Exception
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Triggered by Thread: 0 Filtered syslog:
None found Last Exception Backtrace:
(0x181375900 0x1809e3f80 0x1812641a8 0x181264040 0x1000d0dc0 0x1000d07f0 0x180dc9630 0x180dc95f0 0x180dcecf8 0x18132cbb0 0x18132aa18 0x181259680 0x182768088 0x1860d0d90 0x1000ec1b0 0x180dfa8b8) Global Trace Buffer (reverse chronological seconds):
1.273655 CFNetwork 0x00000001819ef104 TCP Conn 0x126ca8d20 complete. fd: 8, err: 0 // 4: Threads backtraces
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libsystem_kernel.dylib 0x0000000180f18140 0x180efc000 + 115008
1 libsystem_pthread.dylib 0x0000000180fe0ef8 0x180fdc000 + 20216
2 libsystem_c.dylib 0x0000000180e89dac 0x180e28000 + 400812 Thread 1 name: Dispatch queue: com.apple.libdispatch-manager
Thread 1:
0 libsystem_kernel.dylib 0x0000000180f194fc 0x180efc000 + 120060
1 libdispatch.dylib 0x0000000180ddc94c 0x180dc8000 + 84300
2 libdispatch.dylib 0x0000000180dcb7bc 0x180dc8000 + 14268 // 此处省略 // 5: Thread state
Thread 0 crashed with ARM Thread State (64-bit):
x0: 0x0000000000000000 x1: 0x0000000000000000 x2: 0x0000000000000000 x3: 0x00000001256111a1
x4: 0x00000001809daba2 x5: 0x000000016fd95940 x6: 0x000000000000006e x7: 0x00000000000000e0 // 6: Binary images
Binary Images:
0x100068000 - 0x1001fbfff NiuNiu arm64 <136fc60898023e57934bf98a2da74a2e> /var/mobile/Containers/Bundle/Application/A37341B1-FC88-4E49-A102-017A7AE5218C/NiuNiu.app/NiuNiu
0x120020000 - 0x12004ffff dyld arm64 <9e98992ceed735e2ac4784cb28efe7c1> /usr/lib/dyld
0x180964000 - 0x180965fff libSystem.B.dylib arm64 <c4cd04b37e5f34698856a9384aefff40> /usr/lib/libSystem.B.dylib
0x180968000 - 0x1809bbfff libc++.1.dylib arm64 <d430d0ad16893b76bbc52468f65d5906> /usr/lib/libc++.1.dylib
0x1809bc000 - 0x1809dbfff libc++abi.dylib arm64

现在做一下分析:

(1)Process Information

    这部分给出了进程crash后的部分信息

Incident Identifier crash报告的唯一标识

CrashReporter Key crash报告映射到Device Identifier的唯一键值(key)。表面上看上去没有任何含义,但实际上给我们提供了一个有用信息,假如我们所获得的大量crash log拥有同样的Crashreport Key,一定程度上说明这个crash问题并不是普遍存在,也许只是对一些特定的设备存在。

Hardware Model 当前设备类型。假如我们所获得的大量crash log拥有同样的Hardware Model,很大程度上可以说明app在该类设备上运行存在适配的问题。

Process app的名字。

(2)Basic Information

这部分给出了crash的一些基本信息:crash发生的时间,当前设备上操作系统的版本等。如果多数crash log拥有相同的iOS版本号,一定程度上说明app对于该版本iOS系统存在适配问题。

(3)Exception

这部分给出了crash的异常类型,异常错误码和抛出异常的线程。

(4)Threads backtraces

这部分给出了crash时app所有线程的堆栈记录,列出crash时函数调用堆栈。

(5)Thread state

这部分给出了crash时寄存器中的值。事实上,堆栈记录已经提供了类似的信息。

(6)Binary images

这部分列出了crahs时加载的所有文件。

接下来,我们在看一个内存警告的crash log

可以看到,第一部分和之前的crash log内容类似,这里对其他部分的含义作简要的说明:

Free pages 代表可用内存,每个page近似为4KB,故,上面的log里面显示的可用内存为3,872 KB (or 3.9 MB)

Purgeable pages 代表可清除和重用的内存,上面的log显示为0KB

Largest process crash时占用内存最多的应用

Processes 列出进程列表及crash时进程的内存占用情况,包含进程名字,进程唯一标识符,进程使用的page数,app状态(一般情况下引起crash的app拥有frontmost状态)

附录:

这里有一些比较常见的异常码:

1)0x8badf00d  记作“ate bad food”,这个异常一般是因为系统监视器发现超时现象,比如启动或终止超时,亦或者是长时间响应系统时间(event)。
2)0xbad22222 标志VoIP类应用因为频繁启动被终止。
3)0xdead10cc 记作“dead lock”,当应用在后台运行时,由于占用(hold onto)系统资源(比如通讯录数据库),被操作系统终止。
4)0xdeadfa11 记作“deadfall”,标志应用程序可能因为无响应被用户强行终止。

iPhone真机测试Crash信息分析的更多相关文章

  1. iPhone 真机调试应用程序

    原文:http://blog.sina.com.cn/s/blog_68e753f70100r3w5.html 真机调试iphone应用程序 1.真机调试流程概述 1)       真机调试应用程序, ...

  2. [iOS]iPhone进行真机测试(基础版)

    买完688个人开发者账号之后,如何进行真机测试呢??看下面 1.打开https://developer.apple.com 然后,输入我们买过688点那个App ID帐号和密码哦!!一定是要支付过的! ...

  3. unity直连android真机在Profiler性能分析测试

    基础步骤: 1.Unity打开你要测试的项目:File–Build Settings 2.如下图,按图顺序进行1.2.3.4.5操作,如果做过了,2就是灰色的,不能被点击,4和5需要相对应. 3.确保 ...

  4. iOS系列 基础篇 01 构建HelloWorld,剖析并真机测试

    iOS基础 01 构建HelloWorld,剖析并真机测试 前言: 从控制台输出HelloWorld是我们学习各种语言的第一步,也是我们人生中非常重要的一步. 多年之后,我希望我们仍能怀有学习上进的心 ...

  5. iOS真机测试,为Provisioning添加设备 -- based xcode6[原]

    iOS真机测试,  我们需要添加几台新的设备进行测试.我们只需要对Provisioning Profiles 进行更新. 1. 在苹果开发者中心添加测试设备 打开苹果Certificates, Ide ...

  6. iOS - AppRealTest App 真机测试

    前言 1.准备 开发者账号 自从 Xcode7 出来之后,一般的真机测试不需要开发者账号,也就不需要看这篇教程,只有 app 具有 "推送" 等功能的时候,要真机测试就必须要开发者 ...

  7. iOS Developer:真机测试

    如果出现ios development一项为灰色不可点击状态,苹果的说法是 如果您要为此电脑添加证书,请revoke以前的证书后添加,或者通过以前的mac导出证书 原文不记得了,大概这个意思,苹果不希 ...

  8. IOS真机测试(用证书进行真机测试)

    真机测试需要准备 1.证书 2.Iphone或者Ipad 3.到developer.apple.com注册开发者账号(不用money的) ------------------------------- ...

  9. iOS—最全的真机测试教程

    准备 开发者账号 自从Xcode7 出来之后,一般的真机测试不需要开发者账号,也就不需要看这篇教程,只有app具有“推送”等功能的时候,要真机测试就必须要开发者账号和设置证书.苹果只是让你体验一下它的 ...

随机推荐

  1. java design

    http://www.austintek.com/mvc/ http://msdn.microsoft.com/zh-cn/magazine/cc163419.aspx http://www.croc ...

  2. html中混入的特殊字符

    从设计那里拿来的psd中常常会有全角的单双引号. 如果只是拷贝这些字符到做好的html里面,顶多看到乱码再加以改正. 但是,如果是通篇的doc,需要加上各种html语义标签,在拷贝来的doc文字之间加 ...

  3. Struts2之ajax初析

    Web2.0的随波逐流,Ajax那是大放异彩,Struts2框架自己整合了对Ajax的原生支持(struts 2.1.7+,之前的版本可以通过插件实现),框架的整合只是使得JSON的创建变得异常简单, ...

  4. Struts2接收checkbox的值

    Struts2接收checkbox的值:   HTML: <input type="checkbox" name="ssl" value="B1 ...

  5. 【转】如何在github上fork一个项目来贡献代码以及同步原作者的修改 -- 不错

    原文网址:http://www.cnblogs.com/astwish/articles/3548844.html 作为一个IT人,通过github进行学习是最快的成长手段.我们可以浏览别人的优秀代码 ...

  6. 数学(GCD,计数原理)HDU 5656 CA Loves GCD

    CA Loves GCD Accepts: 135 Submissions: 586 Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 2621 ...

  7. 主席树:POJ2104 K-th Number (主席树模板题)

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 44952   Accepted: 14951 Ca ...

  8. 导出Excel文件,npoi方式和通过microsoft.visual basic.dll

    一:例子截图: 二:NPOI截图 三:EmployeeListWindow.cs代码 using System; using System.Collections.Generic; using Sys ...

  9. Ubuntu下安装Skyeye

    ubuntu12下安装skyeye1.3.2 1.首先安装skyeye的依赖包,比如gtk的依赖,一般Ubuntu 都默认安装了,稳妥起见,运行下面的代码: sudo apt-get install ...

  10. CodeForces 595A

    题目链接: http://codeforces.com/problemset/problem/595/A 题意: 一栋楼,有n层,每层有m户,每户有2个窗户,问这栋楼还有多少户没有睡觉(只要一个窗户灯 ...