EXC_BAD_ACCESS信号已收到。

299
在将应用部署到设备时,程序会在几个周期后退出,并显示以下错误:
Program received signal: "EXC_BAD_ACCESS".
程序在iPhone模拟器上没有问题,只要我一步一步执行指令进行调试,它也可以调试和运行。但是,一旦我再次让它运行,就会出现EXC_BAD_ACCESS信号。
在这种情况下,问题出在加速度计代码中。由于模拟器无法执行该代码,因此不会抛出任何错误。然而,在部署到设备上后,它将被执行。
这个问题的大多数答案处理一般的EXC_BAD_ACCESS错误,因此我将把它作为一个涵盖所有可怕的Bad Access错误的开放性问题。 EXC_BAD_ACCESS通常是非法内存访问的结果。您可以在下面的答案中找到更多信息。
您以前遇到过EXC_BAD_ACCESS信号吗?您是如何处理的?
36个回答

201
根据您的描述,我怀疑最有可能的解释是您在内存管理方面出现了一些错误。您说您已经从事iPhone开发几周了,但并没有说明您是否对Objective C有经验。如果您来自其他背景,那么在您真正领会内存管理规则之前可能需要一点时间 - 除非您特别注意这个问题。 请记住,从分配函数(通常是静态分配方法,但还有其他一些方法)或复制方法中获得的任何内容都属于您拥有的内存,在使用完毕后必须释放它。
但是,如果您从任何其他地方获取到东西,包括工厂方法(例如[NSString stringWithFormat]),那么您将拥有一个autorelease引用,这意味着它可能会被其他代码在将来某个时候释放-因此,如果您需要将其保留到超出即时功能的范围之外,那么重点是要对其进行保留(retain)。如果不这样做,内存可能会在您使用时仍保持分配状态,或者在模拟器测试期间被释放但巧合仍然有效,但更有可能在设备上运行时被释放并显示为错误访问。
追踪这些问题的最佳方法,也是一个好主意(即使没有明显的问题),是使用Instruments工具运行应用程序,特别是使用“Leaks”选项。

2
我有一些加速度计采样代码,这对我的应用程序并不重要,但在删除后,消除了错误访问。考虑到模拟器没有加速度计,这是有道理的。我觉得很奇怪的是,在出现这个错误之前,这段代码存在了一个星期而没有被修改... - Héctor Ramos
我对Objective-C很新,所以我的大多数问题应该来自内存管理。在C ++中几年后,我在过去的三到四年中主要使用Java,因此我已经生疏了内存管理。谢谢你的回答! - Héctor Ramos
4
没问题 - 很高兴你解决了它。内存管理其实不难掌握 - 你只需要确保学习规则并养成好习惯即可。 - philsquared
我遇到的问题似乎完全是因为我在释放我创建的字符串(等等)时过于激进。我仍然不确定什么时候应该释放什么,但Phil的答案肯定有所帮助。 - pluckyglen
如果我理解正确的话,cmculloh,是的,那样做是正确的。你不拥有从objectAtIndex返回的对象。 - philsquared

102

EXC_BAD_ACCESS的一个主要原因是尝试访问已释放的对象。

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

即使您不认为自己正在“释放自动释放对象”,这也会适用于您。

此方法非常有效。我经常使用它,并且非常成功!

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

附注:

运行Instruments并检查泄漏将无法帮助排除EXC_BAD_ACCESS。我相当确定内存泄漏与EXC_BAD_ACCESS无关。泄漏的定义是您不再可以访问的对象,因此无法调用它。

更新: 我现在使用Instruments调试泄漏。从Xcode 4.2开始,选择Product->Profile,当Instruments启动时,选择“Zombies”。


18
那个旁注非常重要。泄漏不会引起EXC_BAD_ACCESS(它们有其他问题)。我写这篇文章是为了澄清关于EXC_BAD_ACCESS的误解。http://loufranco.com/blog/files/Understanding-EXC_BAD_ACCESS.html - Lou Franco
4
那个在Xcode中的“zombies工具”太棒了!我仅用了3分钟就找到了罪魁祸首,而不是几个小时。 - Aram Kocharyan
1
以上链接在答案中不可用。显示404未找到错误。 - Tejas
看起来是这个 https://cocoadev.github.io/DebuggingAutorelease/ - Morten J

13

EXC_BAD_ACCESS信号是由于向系统调用传递无效指针而产生的。我今天早些时候在OS X上使用一个测试程序时遇到了这个问题 - 我向pthread_join()传递了一个未初始化的变量,这是由之前的拼写错误导致的。

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


8

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

如果纸面检查都未发现问题,并且单步执行时也没有出现异常,尝试使用NSLog()语句定位错误:在代码中添加这些语句,不断移动它们,直到找到导致错误的行。然后,在该行上设置断点并运行您的程序。当程序停在断点处时,检查所有变量和其中的对象,看是否有任何不符合您的预期。特别要注意那些对象类别与您预期不同的变量。如果一个变量应该包含一个UIWindow,但实际包含了一个NSNotification,那么当调试器未运行时,同样的潜在代码错误可能会以不同的方式表现出来。


7
2010年WWDC视频可以供苹果开发者计划的任何参与者使用。 其中有一段非常棒的视频:"会话311-使用工具进行高级内存分析",其中展示了一些在工具和调试其他内存问题中使用僵尸对象的示例。
点击此处获取登录页面链接:这里

7

我刚刚花了几个小时来跟踪一个EXC_BAD_ACCESS错误,并发现NSZombies和其他环境变量似乎没有告诉我任何有用的信息。

对我来说,问题出在一个愚蠢的NSLog语句上,它带有格式说明符但没有传递参数。

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

修复者

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

我理解你的痛苦。我曾经花了数小时认为问题出在我的最新代码输入上,结果发现一些早期的hack回来咬了我一口。 - leerie simpson

6
我发现在objc_exception_throw上设置断点很有用。这样,当您遇到EXC_BAD_ACCESS时,调试器应该会停下来。
具体操作步骤可以在这里找到:DebuggingTechniques

6

虽然不是完整的答案,但我曾在尝试访问一个由于我尝试使用autorelease而“死亡”的对象时收到此类错误。

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

例如,我曾将此对象作为参数传递给“notify”(将其注册为监听器、观察者或其他你喜欢的说法),但在发送通知时,它已经死亡,导致出现了EXC_BAD_ACCESS错误。将其更改为[[MyNetObject alloc] init],并在适当的时候释放它,可以解决该错误。
另一个原因是,如果你传入一个对象并尝试存储它,也可能会发生这种情况:
myObjectDefinedInHeader = aParameterObjectPassedIn;

稍后尝试访问在标头中定义的myObjectDefinedInHeader时,您可能会遇到麻烦。请使用以下方式:

myObjectDefinedInHeader = [aParameterObjectPassedIn retain];

也许这正是你需要的。当然,这只是我遇到的一些例子,还有其他原因,但它们可能很难捉摸,所以我提一下。祝你好运!


5
另一种在发生EXC_BAD_ACCESS异常之前捕获它们的方法是使用XCode 4+中的静态分析器。可以通过Product > Analyze (shift+cmd+B)运行静态分析器。单击分析器生成的任何消息将在您的源代码上叠加一个图表,显示有问题对象的保留/释放序列。请参考以下内容:static analyzer

enter image description here


5

仅为添加另一种可能性:

我有以下代码:

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

显然,我忘记为字符串分配内存:
NSMutableString *string = [[NSMutableString alloc] init];
[string   appendWithFormat:@"foo"];

解决了这个问题。

这对我来说不会引起任何错误,因为字符串被初始化为nil,并且使用null对象模式在nil上调用方法不会产生任何效果。 - Liron Yahdav

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接