• xcode crash 查找 EXC_BAD_ACCESS 问题根源的方法


    xcode4 4.x

     

    EXC_BAD_ACCESS这个问题一直不好调试,之前有看到过说配置一个环境变量可以很方便的跟踪问题,因此试了一下,发现还真是方便了很多,以下是XCODE 4的配置方法:

    Edit Scheme->Arguments->Environment variables

    增加 NSZombieEnabled ,设置为YES,并勾选上,OK,再次运行,在console就会显示出出错的地方了.

    (另外:

    NSLog(@"id : %@",id);    //id is integer,should be printed as %d

    像这样的语句也会引起EXC_BAD_ACCESS,大家要注意了哦

    )

     

     

     

     

    xcode 3.x.x

    http://www.cocoachina.com/macdev/objc/2011/0219/2661.html

    写程序遇到 Bug 并不可怕,大部分的问题,通过简单的 Log 或者 代码分析并不难找到原因所在。但是在 Objective-C 编程中遇到 EXC_BAD_ACCESS 问题的时候,通过简单常规的手段很难发现问题。

        写程序遇到 Bug 并不可怕,大部分的问题,通过简单的 Log 或者 代码分析并不难找到原因所在。但是在 Objective-C 编程中遇到 EXC_BAD_ACCESS 问题的时候,通过简单常规的手段很难发现问题。这篇文章,给大家介绍一个常用的查找 EXC_BAD_ACCESS 问题根源的方法。

        首先说一下 EXC_BAD_ACCESS 这个错误,可以这么说,90%的错误来源在于对一个已经释放的对象进行release操作。举一个简单的例子来说明吧,首先看一段Java代码:

    public class Test{
            public static void main(String[] args){
                    String s = “This is a test string”;
                    s = s.substring(s.indexOf(“a”),(s.length()));
                    System.out.println(s);
                    
            }
    }

        这种写法在Java中很常见也很普遍,这不会产生任何问题。但是到了 Objective-C 中,就会出事,考虑这个程序:

    #import <Foundation/Foundation.h>

    int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
            NSString* s = [[NSString alloc]initWithString:@”This is a test string”];
            s = [s substringFromIndex:[s rangeOfString:@"a"].location];//内存泄露
            [s release];//错误释放
    [pool drain];//EXC_BAD_ACCESS
    return 0;
    }


        这个例子当然狠容易的看出问题所在,如果这段代码包含在一个很大的逻辑中,确实容易被忽略。Objective-C 这段代码有三个致命问题:1、内存泄露;2、错误释放;3、造成 EXC_BAD_ACCESS 错误。

        1, NSString* s = [[NSString alloc]initWithString:@”This is a test string”]; 创建了一个 NSString Object,随后的 s = [s substringFromIndex:[s rangeOfString:@"a"].location]; 执行后,导致创建的对象引用消失,直接造成内存泄露。

        2,错误释放。[s release]; 这个问题,原因之一是一个逻辑错误,以为 s 还是我们最初创建的那个 NSString 对象。第二是因为从 substringFromIndex:(NSUInteger i) 这个方法返回的 NSString 对象,并不需要我们来释放,它其实是一个被 substringFromIndex 方法标记为 autorelease 的对象。如果我们强行的释放了它,那么会造成 EXC_BAD_ACCESS 问题。

        3, EXC_BAD_ACCESS。由于 s 指向的 NSString 对象被标记为 autorelease, 则在 NSAutoreleasePool 中已有记录。但是由于我们在前面错误的释放了该对象,则当 [pool drain] 的时候,NSAutoreleasePool 又一次的对它记录的 s 对象调用了 release 方法,但这个时候 s 已经被释放不复存在,则直接导致了 EXC_BAD_ACCESS问题。

        那么,知道了 EXC_BAD_ACCESS 的诱因之一后,如何快速高效的定位问题?

    1: 为工程运行时加入 NSZombieEnabled 环境变量,并设为启用,则在 EXC_BAD_ACCESS 发生时,XCode 的 Console 会打印出问题描述。

    首先双击 XCode 工程中,Executables 下的 可执行模组,

    在弹出窗口中,Variables to be set in the environment,添加 NSZombieEnabled,并设定为 YES,点击选中复选框启用此变量。

        这样,运行上述 Objective-C 时会看到控制台输出:Untitled[3646:a0f] *** -[CFString release]: message sent to deallocated instance 0x10010d340

        这条消息对于定位问题有很好的提示作用。但是很多时候,只有这条提示是不够的,我们需要更多的提示来帮助定位问题,这时候再加入 MallocStackLogging 来启用malloc记录。


        当错误发生后,在终端执行:

    malloc_history ${App_PID} ${Object_instance_addr}

        则会获得相应的 malloc 历史记录,比如对于上一个控制台输出

    Untitled[3646:a0f] *** -[CFString release]: message sent to deallocated instance 0x10010d340

        则我们可以在终端执行,结果如下:

    Buick-Wongs-MacBook-Pro:Downloads buick$ malloc_history 3646 0x10010d340
    malloc_history Report Version: 2.0
    Process: Untitled [3646]
    Path: /Users/buick/Desktop/Untitled/build/Debug/Untitled
    Load Address: 0×100000000
    Identifier: Untitled
    Version: ??? (???)
    Code Type: X86-64 (Native)
    Parent Process: gdb-i386-apple-darwin [3638]

    Date/Time: 2011-02-01 15:07:04.181 +0800
    OS Version: Mac OS X 10.6.6 (10J567)
    Report Version: 6

    ALLOC 0x10010d340-0x10010d357 [size=24]: thread_7fff70118ca0 |start | main | objc_msgSend | lookUpMethod | prepareForMethodLookup | _class_initialize | +[NSString initialize] | objc_msgSend | lookUpMethod | prepareForMethodLookup | _class_initialize | NXCreateMapTableFromZone | malloc_zone_malloc
    —-
    FREE 0x10010d340-0x10010d357 [size=24]: thread_7fff70118ca0 |start | main | objc_msgSend | lookUpMethod | prepareForMethodLookup | _class_initialize | _finishInitializing | free

    ALLOC 0x10010d340-0x10010d357 [size=24]: thread_7fff70118ca0 |start | main | -[NSPlaceholderString initWithString:] | objc_msgSend | lookUpMethod | prepareForMethodLookup | _class_initialize | _class_initialize | +[NSMutableString initialize] | objc_msgSend | lookUpMethod | prepareForMethodLookup | _class_initialize | NXCreateMapTableFromZone | malloc_zone_malloc
    —-
    FREE 0x10010d340-0x10010d357 [size=24]: thread_7fff70118ca0 |start | main | -[NSPlaceholderString initWithString:] | objc_msgSend | lookUpMethod | prepareForMethodLookup | _class_initialize | _class_initialize | _finishInitializing | free

    ALLOC 0x10010d340-0x10010d35f [size=32]: thread_7fff70118ca0 |start | main | -[NSCFString substringWithRange:] | CFStringCreateWithSubstring | __CFStringCreateImmutableFunnel3 | _CFRuntimeCreateInstance | malloc_zone_malloc

        这样就可以很快的定位出问题的代码片段了,注意输出的最后一行,,,这行虽然不是问题的最终原因,但是离问题点已经很近了,随着它找下去,八成就会找到问题。
     

     

    分享到:  
    • 相关阅读:
      AS将一个项目导入到另一个项目中
      Android Studio出现:Cause: unable to find valid certification path to requested target
      小米手机Toast带app名称
      PopupWindow 点击外部区域无法关闭的问题
      EditText inputType类型整理
      Fragment通过接口回调向父Activity传值
      Android selector一些坑
      Installation failed with message Failed to commit install session 634765663 with command cmd package
      旷视上海研究院机器人方向招聘
      语义SLAM的数据关联和语义定位(四)多目标测量概率模型
    • 原文地址:https://www.cnblogs.com/moonvan/p/2379666.html
    Copyright © 2020-2023  润新知