接收到EXC_BAD_ACCESS信号

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

Program received signal: "EXC_BAD_ACCESS".

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

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

这个问题的大多数答案都处理一般的EXC_BAD_ACCESS错误,所以我将把这个打开,作为可怕的坏访问错误的一网打尽。

EXC_BAD_ACCESS通常被抛出作为非法内存访问的结果。你可以在下面的答案中找到更多信息。

你以前遇到过EXC_BAD_ACCESS信号吗?你是如何处理它的?

277386 次浏览

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

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

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

如果这些纸上检查都没有发现任何问题,并且在单步走时也没有发生,那么尝试使用NSLog()语句来定位错误:在代码中添加这些语句,移动它们,直到分离出导致错误的行。然后在该行上设置断点并运行程序。当您到达断点时,检查所有变量和其中的对象,看看是否有什么与您期望的不一样。我会特别留意那些对象类不是你所期望的变量。如果一个变量应该包含一个UIWindow,但它有一个NSNotification,当调试器没有在操作时,相同的底层代码错误可能以不同的方式显示自己。

从你的描述中,我怀疑最有可能的解释是你在内存管理中出现了一些错误。你说你已经在iPhone开发上工作了几个星期,但没有说你是否对Objective C有一般的经验。如果你来自其他背景,在你真正内化内存管理规则之前可能需要一段时间——除非你把它说得很重要。

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

但是如果你从其他任何包括工厂方法(例如[NSString stringWithFormat])中得到一些东西,那么你就会有一个自动释放引用,这意味着它可能在未来的某个时候被其他代码释放-所以如果你需要在直接函数之外保留它,那么保留它是至关重要的。如果不这样做,内存可能在使用时仍然被分配,或者在模拟器测试期间被释放但碰巧仍然有效,但更有可能被释放,并在设备上运行时显示为糟糕的访问错误。

追踪这些东西的最好方法,也是一个好主意(即使没有明显的问题)是在Instruments工具中运行应用程序,特别是带有Leaks选项。

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

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

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

因此,例如,我实际上是把这个作为一个对象传递给“通知”(注册为一个侦听器,观察者,无论你喜欢的习语),但它已经死亡一旦通知被发送,我将得到EXC_BAD_ACCESS。将其更改为[[MyNetObject alloc] init]并在适当的时候释放它解决了这个错误。

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

myObjectDefinedInHeader = aParameterObjectPassedIn;

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

myObjectDefinedInHeader = [aParameterObjectPassedIn retain];

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

在过去的四个小时里,我一直在调试和重构代码来解决这个错误。上面的一篇文章让我发现了这个问题:

< p >属性: startPoint = [[DataPoint alloc] init]; startPoint= [DataPointList objectAtIndex: 0];
. startPoint= [DataPointList: 0] . . . x = startPoint。X - 10;// EXC_BAD_ACCESS

.日志含义 < p >房地产后: startPoint = [[DataPoint alloc] init]; startPoint = [[DataPointList objectAtIndex: 0] retain];< / p >

再见EXC_BAD_ACCESS

在过去的四个小时里,我一直在调试和重构代码来解决这个错误。上面的一篇文章让我发现了这个问题:

属性:

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

非常感谢你的回答。我一整天都在为这个问题发愁。你太棒了!

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

要找出如何排除此故障,请阅读此文档: DebuggingAutoReleasePool < / p >

即使你不认为你在“释放自动释放的对象”,这也适用于你。

这个方法非常有效。我一直在用它,而且非常成功!!

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

旁注:

运行仪器和检查泄漏将无助于排除EXC_BAD_ACCESS故障。我非常确定内存泄漏与EXC_BAD_ACCESS无关。泄漏的定义是您不再具有访问权限,因此不能调用它的对象。

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

再补充一种可能发生这种情况的情况:

我有密码:

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

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

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

解决问题。

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

我刚刚花了几个小时跟踪一个EXC_BAD_ACCESS,发现NSZombies和其他env vars似乎没有告诉我任何东西。

对我来说,这是一个愚蠢的NSLog声明与格式说明符,但没有参数传递。

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

固定的

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

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

说明可以在这里找到DebuggingTechniques

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

我忘记在初始化方法中返回self…;)

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

忘记从dealloc中取出一个非分配的指针。我在我的UINavigationController的rootView上获得了exc_bad_access,但只是有时。我假设问题出在rootView上,因为它在viewDidAppear{}中崩溃了。它只发生在我用坏的dealloc{}发布弹出视图之后,这就是它!

"EXC_BAD_ACCESS"[切换到进程330]现在没有可用的内存来编程:调用malloc不安全

我认为这是一个问题,我试图分配…不是在我试图释放非alloc的地方,天哪!

再补充一下

Lynda.com有一个很棒的DVD叫

iPhone SDK基本培训 .

第6章,第3课是关于EXEC_BAD_ACCESS和僵尸的工作。

这对我来说是很好的理解,不仅是错误代码,而且我如何使用僵尸来获得更多关于释放对象的信息。

这是一个很好的帖子。以下是我的经验:我在属性声明中搞砸了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;

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

EXC_BAD_ACCESS恰好出现在方法的入口点之后,让我困惑了好一阵子,因为它不在数组声明附近。

也许其他人能从我这几个小时的拔头发中获益。

运行应用程序,在它失败后(应该显示“;中断”;而不是"EXC_BAD_ACCESS"…检查控制台(运行>控制台)…现在应该有一条消息告诉它要访问什么对象。

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

要获得登录页面的链接,请单击在这里

检查错误可能是什么

使用NSZombieEnabled。

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

选择项目>编辑活动可执行文件打开可执行文件信息窗口。 点击参数。 点击“Variables to be set in the environment”部分中的添加(+)按钮。 “名称”一栏输入“NSZombieEnabled”,“值”一栏输入“YES”。 确保NSZombieEnabled条目的复选标记被选中

我在iphoneonesdk上找到了这个答案

我意识到这是一段时间前被问到的问题,但在阅读这篇文章后,我找到了XCode 4.2的解决方案: Product -> Edit Scheme -> Diagnostics Tab ->启用僵尸对象

. Product -> Edit Scheme -> Diagnostics Tab ->启用僵尸对象

帮助我找到一个消息被发送到一个释放对象。

XCode 4及以上版本,它已经通过Instruments变得非常简单了。在仪器中运行僵尸。本教程解释得很好:调试exc_bad_access错误xcode工具

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

用这个:

@"Some String"

而不是这样:

"Some String"

PS——通常是在用大量记录填充array的内容时。

甚至还有另一种可能:在队列中使用块,可能很容易发生你试图访问另一个队列中的对象,这个对象此时已经被取消分配了。通常当你试图向GUI发送一些东西时。 如果异常断点设置在一个陌生的位置,那么这可能是原因所在。< / p >

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

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

enter image description here

我得到它,因为我没有使用__abc0和-(void) prepareForSegue:(UIstoryboardSegue *)

我如何处理EXC_BAD_ACCESS

有时候我觉得当一个EXC_BAD_ACCESS错误被抛出时,xcode会在主代码中显示错误。m类没有提供崩溃发生的额外信息(有时)。

在这种情况下,我们可以在Xcode中设置一个异常断点,这样当异常被捕获时,就会设置一个断点,并直接通知用户崩溃已经发生在那一行

enter image description here

当你有无限递归的时候,我认为你也会有这个错误。这是我的案子。

在我的例子中,它是由tableview删除操作引起的。这个解决方案解决了我的坏访问异常:https://stackoverflow.com/a/4186786/538408

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

产品->清洁

然后再跑。这对我很管用。否则,我会浪费好几个小时。

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

   class A: UIView {
 

let b = B()
.
.
}






class B: A {
.
.
}

EXC_BAD_ACCESS

EXC_BAD_ACCESS访问一个已经释放的对象。内核发送这个异常(EXC),表示内存块不能被访问(BAD ACCESS)。

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

如果您正在使用自定义字体,并且以编程方式实例化它们,则如果您之前没有在运行时注册字体,则会发生此错误。

为了确保是这样,Xcode控制台将打印如下内容:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x1d8)
frame #0: 0x0000000180f969cc CoreText`CTFontGetClientObject + 12
...

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
frame #0: 0x000000012341c10e CoreFoundation`CFRelease.cold.1 + 14
frame #1: 0x00000001232ed7bd CoreFoundation`CFRelease + 77
frame #2: 0x0000000128136990 libGSFont.dylib`GSFontGetExtraData + 112
frame #3: 0x0000000135bc8958 UIFoundation`-[UIFont lineHeight] + 9
frame #4: 0x00000001340149f3 UIKitCore`-[UILabel intrinsicContentSize] + 331
...

要注册自定义字体并解决该问题,您可以签出此解决方案:https://stackoverflow.com/a/69756114/3701102