收到EXC_BAD_ACCESS信号


290

将应用程序部署到设备上时,程序将在几个周期后退出,并显示以下错误:

Program received signal: "EXC_BAD_ACCESS".

该程序可以在iPhone模拟器上运行,没有任何问题,只要我一次逐步执行说明,它就会进行调试和运行。一旦让它再次运行,我就会EXC_BAD_ACCESS发出信号。

在这种情况下,加速度计代码恰好是一个错误。它不会在模拟器中执行,这就是为什么它不会引发任何错误的原因。但是,它将在部署到设备后执行。

该问题的大多数答案都涉及一般EXC_BAD_ACCESS错误,因此我将保留所有这些作为对可怕的错误访问错误的综合解决方案。

EXC_BAD_ACCESS通常是由于非法内存访问而抛出的。您可以在下面的答案中找到更多信息。

EXC_BAD_ACCESS以前是否遇到过信号,并且如何处理?

Answers:


196

根据您的描述,我怀疑最可能的解释是您的内存管理有一些错误。您说您已经从事iPhone开发工作了几周,但对于您是否对Objective C有所了解却不是。如果您来自其他背景,则在真正内化内存管理规则之前可能要花一些时间-除非您对此有重点。

请记住,从分配函数(通常是静态alloc方法,但还有一些其他方法)或copy方法获得的任何东西,您也都拥有内存,并且必须在完成后释放它。

但是,如果您从包括工厂方法(例如[NSString stringWithFormat]在内的所有其他事物中得到了回报,那么您将拥有一个自动释放引用,这意味着它可以在将来的某个时候由其他代码释放-因此至关重要,如果您需要使它超出保留它的直接功能。如果不这样做,则在您进行模拟器测试期间,内存可能会在使用时保持分配状态,或者被释放但同时仍然有效,但是更有可能被释放并在设备上运行时显示为访问错误。

跟踪这些问题的最佳方法以及一个好主意(即使没有明显的问题)也是一个好主意,那就是在Instruments工具中运行该应用程序,尤其是使用Leaks选项。


2
我有一些加速度计采样代码,这些代码对我的应用而言并不重要,在删除之后,它消除了错误的访问错误。考虑到模拟器没有加速度计,这很有意义。我确实觉得很奇怪,这段代码存在的,不变的,一个星期导致这个错误之前...
赫克托·拉莫斯

我是Objective-C的新手,所以我的大部分问题都应该来自内存管理。在使用C ++几年之后,最近三,四年来我一直在使用Java,因此我对内存管理感到生疏。感谢您的回答!
赫克托·拉莫斯

4
没问题-很高兴您修复了它。内存管理并不是很难真正掌握的-您只需要确保学习规则并养成良好的习惯即可。
philsquared

我遇到的问题似乎完全是因为过于激进地释放了我创建的字符串(或诸如此类)。我仍然不确定要发布什么内容和发布时间,但还是100%不确定,但是Phil的回答肯定会有所帮助。
09年

如果我正确地遵循了cmculloh,是的,这是正确的做法。您不拥有objectAtIndex返回的对象。
philsquared

101

EXC_BAD_ACCESS的主要原因是试图访问已发布的对象。

若要查找如何解决此问题,请阅读以下文档: DebuggingAutoReleasePool

即使您不认为自己是“释放自动释放的对象”,这也将适用于您。

这种方法效果很好。我一直在使用它,并取得了巨大的成功!!

总之,这说明了如何使用Cocoa的NSZombie调试类和命令行“ malloc_history”工具来查找在代码中已访问了哪些已释放对象。

边注:

运行仪器并检查是否有泄漏不会帮助排除EXC_BAD_ACCESS的故障。我很确定内存泄漏与EXC_BAD_ACCESS无关。泄漏的定义是您不再有权访问的对象,因此无法调用它。

更新: 我现在使用仪器调试泄漏。在Xcode 4.2中,选择“产品”->“配置文件”,然后在Instruments启动时选择“僵尸”。


18
该旁注非常重要。泄漏不会导致EXC_BAD_ACCESS(它们还有其他问题)。我写这篇文章是为了消除对EXC_BAD_ACCESS的误解loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html
Lou Franco 2010年

4
Xcode中的僵尸工具很棒!我在3分钟而不是几小时内找到了罪魁祸首。
Aram Kocharyan'3

1
以上答案中的链接不可用。显示404找不到错误。
Tejas

12

EXC_BAD_ACCESS信号是将无效指针传递给系统调用的结果。我今天早些时候在OS X上使用了一个测试程序,因为我有pthread_join()一个较早的错字,所以我向传递了一个未初始化的变量。

我对iPhone的开发不熟悉,但是您应该仔细检查传递给系统调用的所有缓冲区指针。完全提高编译器的警告级别(使用gcc,使用-Wall-Wextra选项)。在模拟器/调试器上启用尽可能多的诊断。


8

以我的经验,这通常是由非法的内存访问引起的。检查所有指针,尤其是对象指针,以确保它们已初始化。如果使用的是MainWindow.xib文件,请确保已正确设置了所有必要的连接。

如果所有的纸上检查都没有发现任何问题,并且单步执行时也没有发生,请尝试使用NSLog()语句查找错误:在代码中撒满代码,四处移动,直到找出导致问题的行。错误。然后在该行上设置一个断点并运行程序。当您达到断点时,请检查所有变量以及其中的对象,以查看是否有什么不符合您的期望。我尤其要注意那些对象类不是您所期望的变量。如果一个变量应该包含一个UIWindow,但其中却包含一个NSNotification,则当调试器不运行时,相同的基础代码错误可能以不同的方式表现出来。


7

我花了几个小时来跟踪EXC_BAD_ACCESS,发现NSZombies和其他env var似乎什么都没告诉我。

对我来说,这是一个愚蠢的NSLog语句,带有格式说明符,但未传递任何参数。

NSLog(@"Some silly log message %@-%@");

固定于

NSLog(@"Some silly log message %@-%@", someObj1, someObj2);

6

苹果开发人员计划的任何参与者都可以使用2010 WWDC视频。有一段很棒的视频:“会议311-使用仪器进行高级内存分析”,显示了一些在仪器中使用僵尸并调试其他内存问题的示例。

要获取登录页面的链接,请点击此处


6

这不是一个完整的答案,但是我收到的一个具体情况是,由于我尝试使用自动释放,试图访问“死”的对象时:

netObjectDefinedInMyHeader = [[[MyNetObject alloc] init] autorelease];

因此,例如,我实际上将其作为“通知”的对象传递(将其注册为侦听器,观察者,无论您喜欢哪种惯用法),但是一旦发送通知,它就已经死了,我将获得EXC_BAD_ACCESS。将其更改为[[MyNetObject alloc] init]并在以后适当时释放它可以解决该错误。

发生这种情况的另一个原因是,例如,如果您传入一个对象并尝试存储它:

myObjectDefinedInHeader = aParameterObjectPassedIn;

稍后,当尝试访问myObjectDefinedInHeader时,您可能会遇到麻烦。使用:

myObjectDefinedInHeader = [aParameterObjectPassedIn retain];

可能正是您需要的。当然,这些只是我遇到的例子中的几个,还有其他原因,但是这些原因可能难以捉摸,因此我将其提及。祝好运!


5

只是添加可能发生这种情况的另一种情况:

我有代码:

NSMutableString *string;
[string   appendWithFormat:@"foo"];

显然我忘记了为字符串分配内存:

NSMutableString *string = [[NSMutableString alloc] init];
[string   appendWithFormat:@"foo"];

解决问题。


这不会对我造成任何错误,因为将字符串初始化为nil并使用null对象模式对nil调用方法没有任何作用。
Liron Yahdav 2014年

5

在异常发生之前捕获EXC_BAD_ACCESS异常的另一种方法是XCode 4+中的静态分析器

使用产品>分析(shift + cmd + B)运行静态分析器。单击分析器生成的任何消息,将在源上覆盖一个图表,该图表显示有问题的对象的保留/释放顺序。

在此处输入图片说明


5

我发现在objc_exception_throw上设置断点很有用。这样,当您获得EXC_BAD_ACCESS时,调试器应该会中断。

可以在这里找到说明调试技术


4

使用“如果不分配或保留它,不要释放它”的简单规则。


1
通过“ ...复制它...”扩展该规则,您应该可以。
直到2012年

4

如何调试EXC_BAD_ACCESS

请查看上面的链接并按说明进行操作。...使用NSZombies的一些快速说明

运行该应用程序,然后运行失败(应显示“ Interrupted”而不是“ EXC_BAD_ACCESS” ...检查控制台(运行>控制台)...现在应该有一条消息,告诉它正在尝试访问的对象。

-本


3

在过去的四个小时中,我一直在调试和重构代码以解决此错误。上面的帖子使我看到了这个问题:

之前的属性:startPoint = [[DataPoint alloc] init]; startPoint = [DataPointList objectAtIndex:0];
。。。x = startPoint.x-10; // EXC_BAD_ACCESS

之后的属性:startPoint = [[DataPoint alloc] init]; startPoint = [[DataPointList objectAtIndex:0]保留];

再见EXC_BAD_ACCESS


我犯了类似的错误。我忘记了造成崩溃的实例,我花了几个小时才弄清楚。你的经历让我发现了我的。谢谢!
David.Chu.ca 2010年

3

希望您在完成后释放“字符串”!


3

我忘了在init-Method中返回自身...;)


这应该是编译时警告/错误,而不是运行时期间的EXC_BAD_ACCESS。
斯蒂吉2014年

3

这是一个很好的线程。这是我的经验:我搞砸了属性声明中的keep / assign关键字。我说:

@property (nonatomic, assign) IBOutlet UISegmentedControl *choicesControl;
@property (nonatomic, assign) IBOutlet UISwitch *africaSwitch;
@property (nonatomic, assign) IBOutlet UISwitch *asiaSwitch;

我应该说的地方

@property (nonatomic, retain) IBOutlet UISegmentedControl *choicesControl;
@property (nonatomic, retain) IBOutlet UISwitch *africaSwitch;
@property (nonatomic, retain) IBOutlet UISwitch *asiaSwitch;

1
奇怪,为什么您需要保留IBOutlet?他们的管理为您自动完成。
jv42 2011年

3

我仅在尝试执行包含大数组的C方法时在iPhone上遇到EXC_BAD_ACCESS。模拟器能够为我提供足够的内存来运行代码,但不能给设备运行(数组是一百万个字符,因此有点多余!)。

EXC_BAD_ACCESS刚好在方法的入口点之后发生,并且让我很困惑,因为它离数组声明不远了。

也许有人可能会从我几个小时的拔头发中受益。


3

忘记从中取出未分配的指针dealloc。我在UINavigationController的rootView上获得了exc_bad_access,但仅​​在某些时候。我认为问题出在rootView中,因为它在其viewDidAppear {}中途崩溃了。事实证明,这只是在我用不良的dealloc {}版本弹出视图之后发生的,仅此而已!

“ EXC_BAD_ACCESS” [切换到过程330]现在没有可用的程序存储器:不安全地调用malloc

我以为这是我要分配的问题……而不是我要发布非分配的问题,D'哦!


3

我如何处理EXC_BAD_ACCESS

有时我觉得抛出EXC_BAD_ACCESS错误时,xcode将在m​​ain.m类中显示该错误,而没有提供崩溃发生位置的额外信息(有时)。

在那种情况下,我们可以在Xcode中设置一个异常断点,以便在捕获异常时放置一个断点,并将直接提示用户该行发生了崩溃。

在此处输入图片说明



2

我只是有这个问题。对我来说,原因是删除了CoreData管理对象,然后尝试从另一个地方读取它。


2

在过去的四个小时中,我一直在调试和重构代码以解决此错误。上面的帖子使我看到了这个问题:

之前的财产:

startPoint = [[DataPoint alloc] init] ;
startPoint= [DataPointList objectAtIndex: 0];
x = startPoint.x - 10; // EXC_BAD_ACCESS

之后的属性:

startPoint = [[DataPoint alloc] init] ;
startPoint = [[DataPointList objectAtIndex: 0] retain];

再见 EXC_BAD_ACCESS

非常感谢您的回答。我整天都在为这个问题而苦苦挣扎。你真棒!


4
您不是立即覆盖startPoint吗?我认为您根本不需要第一行。
toxaq

2
如果您要立即用另一个变量覆盖,则绝对不需要分配和初始化变量。您只是在第一次分配中泄漏了对象。
dreamlax 2010年

2

只是添加

Lynda.com有一张很棒的DVD,名为

iPhone SDK基本培训

第6章,第3课是关于EXEC_BAD_ACCESS以及与僵尸一起工作的。

我很高兴能理解,不仅是错误代码,而且我该如何使用Zombies获取有关已释放对象的更多信息。


2

检查错误可能是什么

使用NSZombieEnabled。

要在应用程序中激活NSZombieEnabled工具:

选择“项目”>“编辑活动的可执行文件”以打开可执行文件的“信息”窗口。单击参数。单击“要在环境中设置的变量”部分中的添加(+)按钮。在“名称”列中输入NSZombieEnabled,在“值”列中输入YES。确保已选中NSZombieEnabled条目的复选标记。

我在iPhoneSDK上找到了这个答案


2

我意识到这是在一段时间前被问到的,但是在阅读了此线程之后,我找到了XCode 4.2的解决方案:产品->编辑方案->诊断选项卡->启用僵尸对象

帮助我找到了发送到已释放对象的消息。


2

当您进行无限递归时,我认为您也可能会遇到此错误。对我来说就是这样。


1

还有另一种可能性:在队列中使用块,很容易发生这种情况,您尝试访问此时已被取消分配的另一个队列中的对象。通常,当您尝试将某些内容发送到GUI时。如果将异常断点设置在一个陌生的地方,则可能是原因。


1

我是因为我没有使用了它[self performSegueWithIdentifier:sender:]-(void) prepareForSegue:(UIstoryboardSegue *)


1

@创建字符串时不要忘记该符号,将其C-strings视为NSStrings会导致EXC_BAD_ACCESS

用这个:

@"Some String"

而不是这样:

"Some String"

PS-通常是在填充array具有大量记录的内容时。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.