收到EXC_BAD_ACCESS信号

时间:2008-11-29 02:50:27

标签: ios cocoa-touch

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

Program received signal: "EXC_BAD_ACCESS".

该程序在iPhone模拟器上运行没有任何问题,只要我逐步执行一个指令,它也将调试和运行。只要我让它再次运行,我就会点击EXC_BAD_ACCESS信号。

在这种特殊情况下,它恰好是加速度计代码中的错误。它不会在模拟器中执行,这就是它没有抛出任何错误的原因。但是,它将在部署到设备后执行。

这个问题的大部分答案都涉及一般的EXC_BAD_ACCESS错误,所以我会把这个问题保留为可怕的Bad Access错误。

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

您之前是否遇到过EXC_BAD_ACCESS信号,以及您是如何处理的?

35 个答案:

答案 0 :(得分:193)

根据您的描述,我怀疑最可能的解释是您的内存管理存在一些错误。你说你已经在iPhone开发工作了几个星期,但不是你是否对Objective C有一般经验。如果你来自另一个背景,你可能需要一段时间才真正内化内存管理规则 - 除非你提出一个重点。

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

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

跟踪这些事情的最佳方式,无论如何都是一个好主意(即使没有明显的问题)是在“工具”工具中运行应用程序,尤其是使用“泄漏”选项。

答案 1 :(得分:99)

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

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

即使您认为自己并未“发布自动发布的对象”,这也适用于您。

此方法非常有效。我一直使用它取得了巨大的成功!!

总之,这解释了如何使用Cocoa的NSZombie调试类和命令行“malloc_history”工具来准确找到代码中已访问的已发布对象。

<强>旁注:

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

<强>更新 我现在使用Instruments来调试泄漏。从Xcode 4.2,选择Product-&gt; Profile,当Instruments启动时,选择“Zombies”。

答案 2 :(得分:12)

EXC_BAD_ACCESS信号是将无效指针传递给系统调用的结果。我今天早些时候在OS X上得到了一个测试程序 - 我正在将一个未初始化的变量传递给pthread_join(),这是由于之前的拼写错误。

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

答案 3 :(得分:8)

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

如果纸上检查都没有进行任何操作,并且在单步执行时不会发生这种情况,请尝试使用NSLog()语句找到错误:将代码随身携带,移动它们直到您将其隔离导致错误的行。然后在该行上设置断点并运行程序。当你点击断点时,检查所有变量及其中的对象,看看是否有任何看起来不像你期望的那样。我会特别留意那些对象类是你没想到的变量。如果一个变量应该包含一个UIWindow,但它中有一个NSNotification,那么当调试器没有运行时,相同的底层代码错误可能以不同的方式表现出来。

答案 4 :(得分:7)

我花了几个小时跟踪EXC_BAD_ACCESS并发现NSZombies和其他env vars似乎没有告诉我任何事情。

对我来说,这是一个带有格式说明符的愚蠢NSLog语句,但没有传递args。

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

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

答案 5 :(得分:6)

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

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

所以例如,我实际上将它作为一个对象传递给'通知'(将其注册为监听器,观察者,你喜欢的任何习惯用法)但是一旦发送通知就已经死了,我就得到了EXC_BAD_ACCESS 。将其更改为[[MyNetObject alloc] init]并在适当的时候释放它可以解决错误。

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

myObjectDefinedInHeader = aParameterObjectPassedIn;

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

myObjectDefinedInHeader = [aParameterObjectPassedIn retain];

可能就是您所需要的。当然,这只是我遇到的几个例子,还有其他原因,但这些可能难以理解,所以我提到它们。祝你好运!

答案 6 :(得分:6)

Apple WWDC视频可供Apple开发者计划的任何参与者使用。 有一个很棒的视频:“会话311 - 使用乐器进行高级内存分析”,其中显示了在乐器中使用僵尸和调试其他内存问题的一些示例。

要获得登录页面的链接,请单击HERE

答案 7 :(得分:5)

在XCode 4 +中,另一种捕获EXC_BAD_ACCESS异常的方法是static analyzer

使用Product&gt;运行静态分析器分析(shift + cmd + B)。 单击分析器生成的任何消息将覆盖源上的图表,显示违规对象的保留/释放顺序。

enter image description here

答案 8 :(得分:5)

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

我有代码:

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

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

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

解决了这个问题。

答案 9 :(得分:5)

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

可以在此处找到说明DebuggingTechniques

答案 10 :(得分:4)

How To Debug EXC_BAD_ACCESS

查看上面的链接并按原样说明....只是一些使用NSZombies的快速说明

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

-Ben

答案 11 :(得分:4)

使用简单的规则“如果您没有分配或保留它,请不要将其释放”。

答案 12 :(得分:3)

这是一个很好的主题。这是我的经验:我在属性声明中搞砸了retain / 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;

答案 13 :(得分:3)

我如何处理EXC_BAD_ACCESS

有时我觉得当抛出EXC_BAD_ACCESS错误时,xcode会在main.m类中显示错误,不会提供崩溃发生位置的额外信息(有时)。

在那些时候,我们可以在Xcode中设置一个异常断点,这样当捕到异常时,将放置一个断点并直接使用户知道该行发生了崩溃

enter image description here

答案 14 :(得分:3)

我在iPhone上遇到EXC_BAD_ACCESS,只是在尝试执行包含大数组的C方法时。模拟器能够给我足够的内存来运行代码,但不是设备(数组是一百万个字符,所以它有点过分!)。

EXC_BAD_ACCESS恰好在方法的入口点之后发生,让我困惑了很长一段时间,因为它远不及数组声明。

也许其他人可能会受益于我几个小时的拔毛。

答案 15 :(得分:3)

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

答案 16 :(得分:3)

希望你在完成后释放'字符串'!

答案 17 :(得分:3)

忘记从dealloc取出一个非分配指针。我在UINavigationController的rootView上获取了exc_bad_access,但有时只是。我认为问题出在rootView中,因为它在viewDidAppear {}中途崩溃了。事实证明,只有在我使用坏的dealloc {}版本弹出视图后才会发生,就是这样!

“EXC_BAD_ACCESS”[切换到进程330]现在没有可用于程序的内存:调用malloc不安全

我认为这是一个问题,我试图分配...而不是我试图释放非分配,D'哦!

答案 18 :(得分:3)

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

之前的财产: 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

答案 19 :(得分:2)

只是添加

Lynda.com有一张名为

的精彩DVD
  

iPhone SDK Essential Training

和第6章,第3课完全是关于 EXEC_BAD_ACCESS 并与Zombies合作。

我很高兴理解错误代码,但是如何使用Zombies获取有关已发布对象的更多信息。

答案 20 :(得分:2)

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

答案 21 :(得分: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

非常感谢您的回答。我整天都在努力解决这个问题。你太棒了!

答案 22 :(得分:2)

检查错误可能是什么

使用NSZombieEnabled。

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

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

我在iPhoneSDK上找到了这个答案

答案 23 :(得分:2)

我意识到这是前一段时间被问过的,但在阅读完这个帖子后,我找到了XCode 4.2的解决方案: 产品 - &gt;编辑方案 - &gt;诊断标签 - &gt;启用Zombie Objects

帮助我找到发送到解除分配对象的消息。

答案 24 :(得分:2)

当你有无限递归时,我认为你也可能有这个错误。这是我的理由。

答案 25 :(得分:2)

验证方法参数的NSAssert()调用对于跟踪和避免传递nils非常方便。

答案 26 :(得分:1)

甚至另一种可能性:在队列中使用块,您可能很容易发生尝试访问另一个队列中的对象,此时此时已经取消分配。通常当您尝试向GUI发送内容时。 如果您的异常断点设置在一个奇怪的地方,那么这可能是原因。

答案 27 :(得分:1)

在你做任何事之前,你应该尝试:

产品 - &gt;清洁

又跑了。它对我有用。否则,我会浪费几个小时。

答案 28 :(得分:1)

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

答案 29 :(得分:1)

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

使用此:

@"Some String"

而不是:

"Some String"

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

答案 30 :(得分:1)

XCode 4及以上版本,使用乐器制作非常简单。只需在仪器中运行Zombies。本教程很好地解释了它:debugging exc_bad_access error xcode instruments

答案 31 :(得分:0)

在我的情况下,它导致了tableview删除操作。此解决方案解决了我的错误访问异常:https://stackoverflow.com/a/4186786/538408

答案 32 :(得分:0)

就我而言,我有一个视图 (A),其中我有另一个视图 (B) 的实例。我忘记了 B 是 A 的子类。显然这会导致递归和无休止的分配。打破这个问题修复了 EXE_BAD_ACCESS 问题。

   class A: UIView {
 
      let b = B()
      .
      .
   }



   class B: A {
     .
     .
   }

答案 33 :(得分:0)

EXC_BAD_ACCESS

EXC_BAD_ACCESS 访问已释放的对象。内核发送此异常(EXC),表示无法访问内存块(BAD ACCESS)。

  • [unowned(unsafe)] 被使用
  • 当一个目标使用具有不同 IPHONEOS_DEPLOYMENT_TARGET[About] 的另一个目标时。在我的例子中,Test target(10.0) 使用了 explicit dependency[About]14.0 IPHONEOS_DEPLOYMENT_TARGET

答案 34 :(得分:0)

尝试在 12 Pro Max 上分配 140000xScreen Height 的 ScrollView 空间时出现 EXC_BAD_ACCESS 错误。它分配得很好,直到达到大约 140,000 像素宽度。 ;)