zoukankan      html  css  js  c++  java
  • (转)xcode 断点调试时候 不能定位到代码那一行的解决办法

    iOS 理解Crash Log

    作为从Android转到iOS的程序员,我觉得最不适应的地方可能就是对bug的定位。在Android中,由于使用Java跑在Java虚拟机上,所以当程序出错时(一般是不会直接操作内存的,所以一般不会有有直接的内存错误),往往是抛出一个异常,关于这个异常的一系列栈信息都能完整的拿到,这对于查找问题的出处来说,就变得非常简单了。

    但是在iOS上,由于使用Objective-c 和 c ,直接执行二进制指令,自己管理内存,会出现访问错误内存的情况出现。这时,系统会直接把你的进程干掉,iOS会给你生成一个Crash Log(如果是调试状态,通常会断在某个地址,基本上没办法判断出错的地方)。以前我基本上不读Crash Log,因为读不懂….iOS的Crash Log不像Android的错误日志,直接告诉你为什么错了,错误在哪个文件第几行(在某些情况下,iOS的CrashLog也能提供这些信息)。最近被逼得没办法了,好好研究了以下Crash Log。主要是看了2010WWDC的Understand Crash Log On iPhone OS,在stackOverFlow上查阅了相关的一些信息,总结如下(有些部分还是没太搞清楚,以后继续完善):

    如何得到一个可读的Crash Report,关于这个,网上有很多,如何symbolicate Crash Log。而且现在Xcode的Orgernizer使用起来非常方便,一般只需要你把Crash Log拖到Orgernizer中,它会自动地给你的Crash Log做Symbolicate。它大概的原理是(我记不得在哪看到的了,但我感觉应该是这样,it make sence),你的每一个crash log是相对应于一个.app版本的,在你的.app中有一个.dSYM文件,当你发布的时候,使用xcode 的build and archive进行发布,这个发布会纪录到你的xcode(或者orgernizer)中,当你把crash log拖到orgernizer时,它会自动去匹配响应版本的.dSYM文件来进行转换,得到各个函数名和在文件中的位置。需要特别强调的是在Xcode中有两个编译选项会特别地影响到Crash Report的生成:
    1.Generate Debug Symbols.当你把这个选项设为YES的时候,生成的Crash Report才能根据.dSYM文件,在出错时,定位到你自己代码的调用信息,否则就只有纯粹的函数地址和偏移量,打开这个设置,会导致你的二进制文件大增变大(据说20%~30%),应该也会营销效率(具体能影响到什么程度我也没有一个量化的概念,但我自己的感觉是区别不是很大)。
    2.Strip Debug Symbols During Copy.这个选项主要是影响在你发布和Debug的时候是否剥去Debug symbols。
    所以,如果希望能得到非常详细的错误信息,应该把前者设为YES,后者设为NO.

    总的来说Crash Report分为四大种类型(我的理解主要是通过exception type和exception code来进行判断是哪一种):
    1.WatchDog Timeout 一般是在启动,恢复等时候,在主线程中做了非常耗时的工作,导致UI阻塞,系统就会把你干掉并声称一个这种类型的Crash Report。exception type:0×000..020 exception code:0x8badf00d.
    2.User Force-quit 用户主动操作把你的程序干掉了。excption code:0xdeadfa11
    3.Low memory termination 由于内存不足被干掉。Low memory所产生的crash log和其他的crash log很不一样,很容易分辨。
    4.Application bugs 本身代码的bug导致的crash。
    另外还有一些exception code在苹果的这个文档中有相应的纪录。

    Crash Report中比较重要的一些信息:
    Incident Identifier 每个崩溃报告拥有一个唯一的标识。
    CrashReporter Key 主要反应这个崩溃报告来自哪一台设备,如果你一系列的崩溃报告都来自同一个CrashReporter Key,那你可以仔细留意以下这台设备的情况。
    Hardware Model 说明这个崩溃报告产生自哪一类型的设备。
    Date/Time 崩溃报告产生的时间。
    OS Version 系统版本。
    Exception Type 异常类型。
    Exception Code 异常码。
    Crashed Thread 崩溃的线程。
    Highlighted Thread 有的时候,这里不是Crash Thread,而是Highlighted Thread。区别?
    Application Specific Information 一些特殊信息,在某些情况下有。比如由于占用系统资源导致被杀掉,这里有可能告诉你是占用了什么系统资源。

    在Thread BackTrace中:
    第一列 这是一列数字,官方貌似叫frame number,我的理解就是最后的调用栈的index.
    第二列 应该是只这个调用所在的库或者framework,具体的名字我没听清楚。
    第三列 函数地址。
    第四列 没听明白,但我感觉这一列是才是函数地址,最后能被symbolicate转换为函数名。后面的+xx是一个偏移量,能定位到在文件中的行数。

    在以上的信息中,又有两个特别的重要的,能帮助我们识别问题大概出在哪。
    1.Exception Type
    -1- EXC_BAD_ACCESS (SIGSEGV) 这个类型的Exception的意思是,你没有权限访问你所要访问的内存。一般都是由于访问了已经被release的object导致的,或者把一个object release了两次(我的理解这和前面的情况是一样的)。甚至当你访问超出数组长度的内容时,也有可能出现这种类型的错误。它的意思应该是段错误。这个SIGSEGV不是objective-c的excption,而是更底层的C部分的信号。
    -2- EXC_CRASH (SIGKILL)或者(SIGABRT) 这个类型的Exception比较特别,你需要认真查看后面所有Thread的BackTrace才能找到最终原因,因为有时候它所写的Crash Thread并不是真正引起崩溃的原因,在其中你也找不到什么有用的信息。(SIGABRT)一般是由于系统捕获到一个异常,然后把你的应用终结掉了,你可以在下面的栈信息中寻找有abort信息的那一个thread,能找到真正的原因。(SIGKILL)目前还没在自己的App中遇到过。

    2.Exception Code
    一般如果是由于有未捕获异常的话,都是0×000000000。如果exception type是0×0000020,那么这个数值可能指代某种具体类型的错误,在上面的文档中有。如果是内存问题,一般会有两种,一种是KERN_INVALID_ADDRESS at 0x…….,一种是KERN_PROTECTION_FAILURE at 0x……。具体区别在这里有人讲了下,但我没太明白实际的区别。

  • 相关阅读:
    Martix工作室考核题 —— 打印一个菱形
    Martix工作室考核题 —— 打印一个菱形
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 打印九九乘法表
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第三题
    Martix工作室考核题 —— 201938 第一题
    fiddler模拟发送post请求
  • 原文地址:https://www.cnblogs.com/AlexHHC/p/3172166.html
Copyright © 2011-2022 走看看