【问题标题】:EXC_BAD_ACCESS signal received收到 EXC_BAD_ACCESS 信号
【发布时间】:2010-09-24 12:48:46
【问题描述】:

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

Program received signal: "EXC_BAD_ACCESS".

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

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

这个问题的大部分答案都涉及一般的EXC_BAD_ACCESS 错误,所以我将把它作为一个全面的开放状态,作为可怕的错误访问错误的全部答案。

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

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

【问题讨论】:

    标签: ios cocoa-touch


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 我有一些对我的应用程序并不重要的加速度计采样代码,在删除后消除了错误的访问错误。考虑到模拟器没有加速度计,这是有道理的。我确实觉得很奇怪,这段代码在导致这个错误之前已经存在了一周,没有受到任何影响......
    • 我是 Objective-C 的新手,所以我的大部分问题应该来自内存管理。在使用 C++ 几年之后,过去三四年我主要使用 Java,所以我对内存管理生疏了。感谢您的回答!
    • 没问题 - 很高兴你修好了。内存管理并不是很难掌握 - 你只需要确保你学习规则并养成良好的习惯。
    • 我遇到的问题似乎完全是因为在发布我创建的字符串(等等)时过于激进。我仍然不能 100% 确定应该发布什么以及何时发布,但菲尔的回答肯定有帮助。
    • 如果我正确地遵循了这一点,cmculloh,是的,这是正确的做法。您不拥有从 objectAtIndex 返回的对象。
    【解决方案2】:

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

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

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

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

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

    旁注:

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

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

    【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

      如果纸上的检查都没有发现任何问题,并且单步执行时也没有发生,请尝试使用 NSLog() 语句定位错误:将它们洒在你的代码中,移动它们直到你隔离导致错误的行。然后在该行设置断点并运行您的程序。当您到达断点时,检查所有变量以及其中的对象,看看是否有任何不符合您预期的情况。我会特别注意其对象类是您没想到的变量。如果一个变量应该包含一个 UIWindow 但它却有一个 NSNotification ,那么当调试器不运行时,相同的底层代码错误可能会以不同的方式表现出来。

      【讨论】:

        【解决方案5】:

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

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

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

        修复者

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

        【讨论】:

        • 我感受到你的痛苦。我花了好几个小时想这一定是我最新的代码条目,结果发现一些早期的黑客又回来咬我了。
        【解决方案6】:

        Apple 开发者计划的任何参与者都可以观看 2010 年 WWDC 视频。 有一个很棒的视频:“Session 311 - Advanced Memory Analysis with Instruments”展示了在仪器中使用僵尸和调试其他内存问题的一些示例。

        点击HERE获取登录页面链接。

        【讨论】:

          【解决方案7】:

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

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

          例如,我实际上将它作为一个对象传递给“通知”(将其注册为侦听器、观察者,无论您喜欢什么成语),但是一旦发送通知,它就已经死了,我会得到 EXC_BAD_ACCESS .将其更改为[[MyNetObject alloc] init] 并在稍后酌情释放它解决了错误。

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

          myObjectDefinedInHeader = aParameterObjectPassedIn;
          

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

          myObjectDefinedInHeader = [aParameterObjectPassedIn retain];
          

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

          【讨论】:

            【解决方案8】:

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

            说明可以在这里找到DebuggingTechniques

            【讨论】:

              【解决方案9】:

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

              我有代码:

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

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

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

              解决问题。

              【讨论】:

              • 这不会对我造成任何错误,因为字符串被初始化为 nil 并且使用空对象模式调用 nil 上的方法什么都不做。
              【解决方案10】:

              在 EXC_BAD_ACCESS 异常发生之前捕获它们的另一种方法是 XCode 4+ 中的 static analyzer

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

              【讨论】:

                【解决方案11】:

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

                【讨论】:

                • 通过“...复制它...”扩展该规则,您应该没问题。
                【解决方案12】:

                How To Debug EXC_BAD_ACCESS

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

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

                【讨论】:

                  【解决方案13】:

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

                  之前的属性: 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

                  【讨论】:

                  • 我犯了类似的错误。我忘记了导致崩溃的实例,我花了几个小时才弄明白。你的经历让我发现了我的。谢谢!
                  【解决方案14】:

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

                  【讨论】:

                    【解决方案15】:

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

                    【讨论】:

                    • 这应该是编译时警告/错误,而不是运行时的 EXC_BAD_ACCESS。
                    【解决方案16】:

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

                    【讨论】:

                    • 奇怪,为什么要保留 IBOutlet?他们的管理是自动为您完成的。
                    【解决方案17】:

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

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

                    也许其他人可能会从我几个小时的拉头发中受益。

                    【讨论】:

                      【解决方案18】:

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

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

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

                      【讨论】:

                        【解决方案19】:

                        我如何处理 EXC_BAD_ACCESS

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

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

                        【讨论】:

                          【解决方案20】:

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

                          【讨论】:

                            【解决方案21】:

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

                            【讨论】:

                              【解决方案22】:

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

                              之前的属性:

                              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

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

                              【讨论】:

                              • 你不是直接覆盖startPoint吗?我认为你根本不需要第一行。
                              • 如果您要立即用另一个变量覆盖它,则绝对不需要分配和初始化一个变量。您只是在第一次分配中泄漏了对象。
                              【解决方案23】:

                              只是添加

                              Lynda.com 有一张很棒的 DVD,叫做

                              iPhone SDK Essential Training

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

                              这对我来说很好理解,不仅仅是错误代码,还有我如何使用 Zombies 来获取有关已发布对象的更多信息。

                              【讨论】:

                                【解决方案24】:

                                检查错误可能是什么

                                使用 NSZombieEnabled。

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

                                选择 Project > Edit Active Executable 以打开可执行信息窗口。 单击参数。 单击“要在环境中设置的变量”部分中的添加 (+) 按钮。 在 Name 列中输入 NSZombieEnabled,在 Value 列中输入 YES。 确保选中 NSZombieEnabled 条目的复选标记。

                                我在 iPhoneSDK 上找到了这个答案

                                【讨论】:

                                  【解决方案25】:

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

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

                                  【讨论】:

                                    【解决方案26】:

                                    当你有无限递归时,我想你也会有这个错误。这对我来说就是一个案例。

                                    【讨论】:

                                      【解决方案27】:

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

                                      【讨论】:

                                        【解决方案28】:

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

                                        【讨论】:

                                          【解决方案29】:

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

                                          使用这个:

                                          @"Some String"
                                          

                                          而不是这样:

                                          "Some String"
                                          

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

                                          【讨论】:

                                            【解决方案30】:

                                            XCode 4 及更高版本,使用 Instruments 变得非常简单。只需在 Instruments 中运行 Zombies。本教程解释得很好:debugging exc_bad_access error xcode instruments

                                            【讨论】:

                                              猜你喜欢
                                              • 2011-07-17
                                              • 1970-01-01
                                              • 2011-03-06
                                              • 1970-01-01
                                              • 1970-01-01
                                              • 1970-01-01
                                              • 2011-05-08
                                              相关资源
                                              最近更新 更多