`
sinkzephyr
  • 浏览: 89605 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

(转)查找 EXC_BAD_ACCESS 问题根源的方法

阅读更多

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

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

        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);
        }
}

#import
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 错误。

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

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

首先双击 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


下面还有一个更极端的方法:

有时程序崩溃根本不知错误发生在什么地方。比如程序出现EXEC_BAD_ACCESS的时候,虽然大部分情况使用设定 NSZombieEnabled环境变量可以帮助你找到问题的所在,但少数情况下,即使设定了NSZombieEnabled环境变量,还是不知道程序崩溃在什么地方。那么就需要使用下列代码进行帮助了:



#ifdef _FOR_DEBUG_
-(BOOL) respondsToSelector:(SEL)aSelector {
    printf("SELECTOR: %s\n", [NSStringFromSelector(aSelector) UTF8String]);
    return [super respondsToSelector:aSelector];
}
#endif

你需要在每个object的.m或者.mm文件中加入上面代码,并且在other c flags中加入-D _FOR_DEBUG_(记住请只在Debug Configuration下加入此标记)。这样当你程序崩溃时,Xcode的console上就会准确地记录了最后运行的object的方法。



直接用Category覆盖NSObject的这个方法可能会更好。


http://ibuick.com/buick2011820/index.php/archives/objective-c-exc_bad_access

 

分享到:
评论

相关推荐

    查找 EXC_BAD_ACCESS 问题根源的方法

    ### 查找 EXC_BAD_ACCESS 问题根源的方法 #### 一、EXC_BAD_ACCESS 错误简介 EXC_BAD_ACCESS 是一种常见的 Objective-C 编程错误,通常发生在试图访问已释放或未分配的内存时。这类错误往往难以追踪,因为它们可能...

    查找EXC_BAD_ACCESS的错误代码处

    ### 查找EXC_BAD_ACCESS错误代码处:利用Instrument工具定位问题 #### 一、引言 在软件开发过程中,特别是iOS应用开发中,经常会遇到难以捉摸的内存管理问题,其中最常见的之一就是`EXC_BAD_ACCESS`错误。这种类型...

    ios EXC_BAD_ACCESS错误调试

    在iOS开发中,EXC_BAD_ACCESS错误是一种常见的运行时错误,通常是因为程序尝试访问已被释放的内存地址导致的。当程序尝试访问一个已经释放的对象时,系统就会抛出EXC_BAD_ACCESS错误,这在C语言中通常被理解为使用了...

    关于出现僵尸信号SIGBAT或者EXC_BAD_ACCESS的解决方案

    总结来说,解决SIGABRT和EXC_BAD_ACCESS错误需要理解iOS的内存管理机制,启用僵尸模式来定位问题,使用Instruments工具进行深入分析,并审查代码中的对象生命周期管理。对于storyboardDemo项目,通过模拟用户操作和...

    iOS内存错误EXC_BAD_ACCESS的解决方法

    iOS开发,最郁闷的莫过于程序毫无征兆地就崩溃了,用bt命令打出调用栈,给出的是一堆系统EXC_BAD_ACCESS的信息,根本没办法定位问题出现在哪里。 首先说一下 EXC_BAD_ACCESS 这个错误,可以这么说,90%的错误来源...

    db2exc_975_WIN_x86.exe

    db2exc_975_WIN 数据库安装包,官网下载,亲测可用。 IBM DB2 是一套关系型数据库管理系统,DB2 Express - C

    db2exc_970_LNX_x86_64.tar.z01

    db2exc_970_LNX_x86_64.tar.gz Linux 64位系统 的db2 安装包。(第一部分)

    db2exc_970_LNX_x86_64.tar.zip

    db2exc_970_LNX_x86_64.tar.gz Linux 64位系统 的db2 安装包。(第二部分) 另一部分:https://download.csdn.net/download/qq_37570669/11260296

    Python使用sys.exc_info()方法获取异常信息

    在实际调试程序的过程中,有时只获得异常的类型是远远不够的,还需要...模块 sys 中,有两个方法可以返回异常的全部信息,分别是 exc_info() 和 last_traceback(),这两个函数有相同的功能和用法,本节仅以 exc_info

    code_file_exc_电磁波_

    这个"code_file_exc_电磁波_"的压缩包文件很可能包含了一系列用于进行电磁波时域有限元分析的代码,帮助我们理解和模拟电磁波的行为,确保波形的准确性和不失真性。 时域有限元方法(Finite Element Method, FEM)...

    inh-exc_neuron_oscillation_

    标题“inh-exc_neuron_oscillation_”暗示了我们正在探讨神经网络中抑制性与兴奋性神经元之间的交互,特别是关于它们如何引发振荡的现象。描述中的“excitatory neuron connection”进一步指出了兴奋性神经元间的...

    Data_Extract_src.zip_Excel数据提取_VB_VB提取excel数据_extract exc_提取exce

    标题 "Data_Extract_src.zip_Excel数据提取_VB_VB提取excel数据_extract exc_提取excel" 描述了一个使用VB.NET编程语言编写的程序,该程序能够自动从Excel文件中提取数据。这个项目可能是一个实用工具,帮助用户快速...

    将ADO数据转换到EXCEL的代码.rar_ado EXC_ado excel_excel ado

    首先,ADO提供了一种灵活的方式来连接和操作各种数据源,包括SQL Server、Access、Oracle等。它通过记录集(Recordset)对象作为数据访问的主要接口,记录集可以看作是数据库中的一张表或查询结果的动态视图。 1. ...

    DB2_V9.7在linux上安装教程

    1、tar -xzvf db2exc_nlpack_970_LNX_x86.tar.gz 得到文件夹nlpack 2、tar -xzvf v9.7_linuxia32_server.tar.gz 得到文件夹server 二、 语言包整合 cp -r nlpack/* ./server/ 三、 安装 1、cd server 2、sudo ./...

    cad2excel.rar_ excel cad_AutoCAD VBA_Cad2Exc_VBa_cad-excel

    CAD to Excel VBA程序 AutoCAD中的二次开发程序

    calculate.rar_Excel VBA_VBA calculate_calculate exc_工程量汇总vba_工程量

    excel做的传统工程量计算表(加入vba后能自动计算、汇总、标注说明) 1、序号根据填入的分部分项名称自动填出1~N的数值。 2、代码栏根据填入的数据自动给出同一分部分项名称序号,为汇总提供方便。...

    ios-GPUImageFiltersCamera.zip

    出现EXC_BAD_ACCESS。 需要修改Product->Scheme->Edit Scheme->Options->GPU Frame Capture 选择 Disabled。 功能介绍 模仿Filckr的照相功能实现了: 1.实时滤镜 2.相机基本功能:拍照,对焦,前后...

    CK_EXC_UnityGraphicBeginner

    本教程“CK_EXC_UnityGraphicBeginner”将引导你入门Unity中的图形编程,让你逐步掌握在Unity中创建、操纵和优化图形的技术。 一、Unity基础 Unity的工作界面由多个面板组成,包括项目面板、资产面板、层次面板、...

Global site tag (gtag.js) - Google Analytics