什么是EXC_BAD_ACCESS以及如何调试

时间:2021-02-04 23:00:57

某些时候,你可能会遇到由EXC_BAD_ACCESS引起的崩溃。在这片文章中,你将学会什么是EXC_BAD_ACCESS,以及它是由什么引起的。我也将提出一些解决由EXC_BAD_ACCESS引起的bug的技巧。

什么是EXC_BAD_ACCESS?

一旦你理解了EXC_BAD_ACCESS的根本原因,你会更好地理解它这个含义模糊的名称。这里有一个简单的解释和一个更加专业的解释。让我们首先以这个简单的解释开始吧。

保持简单

无论何时你遇到了EXC_BAD_ACCESS,那就意味着你正在发送一个消息给一个对象,而这个对象已经被释放掉了。这是最常见的情况,但是下面来看看更多的解释。

真正含义

专业的解释有一些复杂。在C和Objective-C中,经常处理指针。指针无非是存储另一个变量的内存地址的变量。当你发送一个消息给一个对象,那么指向这个对象的指针需要被引用。这意味着,你取得这个指针指向的内存地址而且访问那块内存的值。

当那块内存不再与你的应用程序映射,或者,换一种说法,那块内存不再以你所期许的方式被使用,那么,就有可能无法访问到那一块内存。当这种情况发生的时候,内核发送异常( EXC ),表明你的应用程序无法访问到那块内存(BAD ACCESS)。

概括起来就是:当你遇到EXC_BAD_ACCESS时,意味着你在尝试向一块内存发送消息,而这块内存无法执行这个消息。

然而,有时候,EXC_BAD_ACCESS是由一个corrupt pointer(即野指针)引起的。每当你的应用程序程序尝试去引用一个corrupt pointer指针时,内核都会抛出一个异常。

注:corrupt pointer:可以理解为『野指针』。指的是:指向一个已删除的对象或未申请访问受限内存区域的指针。与空指针不同,野指针无法通过简单地判断是否为 NULL避免,而只能通过养成良好的编程习惯来尽力减少。对野指针进行操作很容易造成程序错误。

调试EXC_BAD_ACCESS

调试EXC_BAD_ACCESS可能是棘手和令人沮丧的。显示,现在EXC_BAD_ACCESS对你来说不再是那么困难的事情了。

你需要了解的第一件事情是,一旦内存块无法被访问到,你的应用程序就会崩溃。这就是使调试EXC_BAD_ACCESS这么困难的原因。

同样的,当你引用野指针时,情况就糟糕了。

Zombies

虽然僵尸在过去的几年中才得到普及,但是,在Xcode中以及出现十多年了。『僵尸』这个名称听起来可能有些戏剧化,但是,这对于解释我们是如何调试EXC_BAD_ACCESS来说,是一个体现其特性的伟大的名字。

在Xcode中,你可以启用僵尸对象(zombie objects),这意味着,被释放的对象作为『僵尸』来被保持。换句话说,被释放的对象为了调试程序而被保持活跃。这没有什么神奇的作用。如果你将消息发送给一个僵尸对象,你的应用程序仍然会得到一个EXC_BAD_ACCESS的崩溃。

为什么启用zombie是有用的?让EXC_BAD_ACCESS难以调试的原因是:你不知道你的应用程序尝试去访问的对象是什么。在多种情况下,僵尸对象能够解决这个问题。通过使被释放的对象保持活跃,Xcode能够告诉你应用程序试图访问的对象,并使问题的检索更加简单。

在Xcode中启用Zombies很简单。注意,你的Xcode版本不同可能导致方法不同。以下方法适用于Xcode 6 和Xcode 7.选择工具条中的Product-> 选择 Scheme -> 选择 Edit Scheme。或者使用快捷方式Command+<

选择左侧的Run,打开顶部标签中的Diagnotics(诊断),勾选复选框Enable Zombie Objects。
什么是EXC_BAD_ACCESS以及如何调试

如果现在遇到EXC_BAD_ACCESS,Xcode控制台的输出会给你一个从哪里开始检索错误的更好的建议。看看下面的例子:

2015-08-12 06:31:55.501 Debug[2371:1379247] -[ChildViewController respondsToSelector:] message sent to deallocated instance 0x17579780

在上面的例子中,Xcode是在告诉我们,这个消息respondsToSelector:被发送给一个僵尸对象。然而,僵尸对象不再是ChildViewController类的一个实例对象。之前分配给ChildViewController实例对象的内存块不再与你的应用程序所映射。这对你认识问题的根本原因有所帮助。

不幸的是,僵尸对象不能解决你所遇到的任何由EXC_BAD_ACCESS所引起的崩溃。如果僵尸对象不能解决你的问题,那么试着去做一些分析。

剖析

如果僵尸对象不能帮助你,那么根本原因则是很重要的。这种情况下,你应该仔细看看你的应用程序崩溃时正在执行的代码。这个过程有可能是耗时而麻烦的。

为了帮你找到你的代码中得问题,你可以让Xcode分析你的代码,以帮你找到问题区间。注意,Xcode分析你的项目,可能会指出它遇到的任何一个潜在的问题。

选择Product->Analyze,或者快捷方式Shift+Command+B,来启用Xcode对你的项目的分析。

这可能消耗Xcode几分钟时间,但是,当它完成的时候,你会在左侧的问题导航器中看到问题清单。通过分析发现的问题以蓝色高亮显示。
什么是EXC_BAD_ACCESS以及如何调试

当你点击一个问题时,Xcode定位到需要你注意的那块代码。需要注意的是,Xcode只是提出建议,某些时候,有可能问题是不相干的,或者不需要你去解决的。
什么是EXC_BAD_ACCESS以及如何调试

如果你不能找到引起EXC_BAD_ACCESS的bug,那么仔细检查Xcode在分析过程中找到的问题就很重要了。

结论

EXC_BAD_ACCESS是开发人员共同面临的挫折,这是手动内存管理所特有的东西。自推出ARC之后,内存管理相关的问题出现的频率比较低了,但是,它们并没有消失。

本篇文章翻译自:http://code.tutsplus.com/tutorials/what-is-exc_bad_access-and-how-to-debug-it–cms-24544