EXC_BAD_ACCESS,但没有僵尸对象,并且不是在调试构建配置中。

8 浏览
0 Comments

EXC_BAD_ACCESS,但没有僵尸对象,并且不是在调试构建配置中。

这真让我抓狂。我第一次将我的应用程序上传到App Store,然后,当然,现在我的应用程序左右摇摆不定。当我使用发布版本配置进行构建时,我在一段时间后随机获得一个EXC_BAD_ACCESS错误。我已经打开了Zombies选项,但问题似乎不是因为释放了一个变量,因为我没有收到关于向一个已释放变量发送消息的消息。

错误总是出现在我的代码的同一个位置。看起来我试图保留一个没有正确初始化的变量。我一点也不知道我怎么会做到这一点。

但是奇怪的是:如果我使用调试发布配置进行构建,它从不崩溃。我可以一整天都进行测试,它非常稳定。但是如果我使用发布配置构建,它就会时不时地崩溃。

查看两个配置的构建设置,差异并不多。在调试中,GCC 4.0的优化级别是“None”,而在发布中是“Fastest, Smallest”。如果我将发布中的优化级别切换为“None”,应用程序就表现正常。有人知道我应该寻找什么来修复这个问题吗?或者,如果我没有进行优化分发,会发生多少不好的事情?

更新:

该死!我真的需要一个用于内存错误的神奇调试工具。我已经在过去一天左右解决了这个问题。我添加了一个可靠地生成崩溃的exercise方法,并开始寻找引起崩溃的代码区域。

该应用程序通常在执行特定类型的操作第3-5次时崩溃。该类型的操作唯一不同的是我从一个附属方法返回的值。附属方法通常返回值为0-3的NSDecimalNumber,但有一种特殊情况下,我返回一个非整数值的NSDecimalNumber。我会测试附属方法的结果,寻找非整数值。我将特殊情况更改为返回值为-1的NSDecimalNumber,现在我无法再使应用程序崩溃。

基本上,我只做了一个改变,从

[[NSNumber numberWithDouble:num] decimalValue] --> 崩溃

[[NSNumber numberWithInteger:num] decimalValue] --> 无崩溃

虽然比这更复杂一些,但不多。

现在,我很高兴应用程序不再崩溃,但我对我所做的改变并不充满信心,因为旧的代码片段在任何方面都没有出现“问题”。所以,尽管我的应用程序不再崩溃,但并不是因为我“修复”了它,我只是随机改变了一些东西,现在它可以正常工作了。8^(

更新:

调试器在程序崩溃时没有像通常那样输出堆栈跟踪。当它崩溃时,调试控制台输出以下内容:

将程序加载到调试器中...

[...版权信息...]

This GDB was configured as "i386-apple-darwin".warning: Unable to read symbols for "/System/Library/Frameworks/UIKit.framework/UIKit" (file not found).

warning: Unable to read symbols from "UIKit" (not yet mapped into memory).

warning: Unable to read symbols for "/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics" (file not found).

warning: Unable to read symbols from "CoreGraphics" (not yet mapped into memory).

Program loaded.

sharedlibrary apply-load-rules all

Attaching to program: `/Users/...', process 10066.

Re-enabling shared library breakpoint 1

Cannot access memory at address 0x4

Cannot access memory at address 0x4

(gdb)

0
0 Comments

【原因】

(EXC_BAD_ACCESS, but with no zombies, and not in debug build configuration)问题的出现原因是指针类型的错误使用,即将整数转换为指针或将指针转换为整数时没有进行正确的类型转换。

【解决方法】

1. 打开项目设置,提高编译器的警告级别,确保开启所有的警告选项。

2. 或者找到项目设置中名为"Other C Flags"的项目设置,并添加-Wall -Wextra这两个标志。

3. 通过增加警告级别,会出现大量的警告信息,如有符号/无符号不匹配、可能的精度丢失等,大部分情况下可以忽略这些警告。但是有一些关键的警告需要引起注意,比如在没有进行正确类型转换的情况下,将整数转换为指针(或反之)。如果不确定是否可以忽略警告,应该修复代码以消除警告。

4. 需要注意有符号/无符号比较可能会导致意想不到的问题。确保在使用时选择正确的符号,这通常并不难。精度问题通常不会引起太多问题,但很容易修复,只需打开警告并进行修复(通常需要向常量添加"f"以标识其为浮点数而不是双精度数)。在"使用访问器"之后,改善代码并减少调试时间的第二个法则是"将警告视为错误"。

5. 当然,有时候有符号/无符号不匹配可能会带来严重问题,但往往它们是无害的,比如"for(int i = 0; i < foo.size(); i++)",其中foo.size()返回的是size_t类型。

通过以上方法,可以解决(EXC_BAD_ACCESS, but with no zombies, and not in debug build configuration)问题的出现。

0
0 Comments

在发布应用程序时,经常会出现(EXC_BAD_ACCESS)错误,但没有僵尸对象,并且不在调试构建配置中。这种错误的出现原因可能是内存错误,而僵尸对象工具并不能检测到所有这种类型的错误。对于内存错误,没有一个魔术的调试工具,只能通过仔细的编程来避免(并且有一些模式可以使这些错误变得更不常见,并且在发生时更容易调试)。

优化代码可能会引发一些在非优化代码中不会出现的问题。这可能意味着问题是一个局部变量而不是一个实例变量,但也可能不是。这可能只是一个时机问题;速度更快可能会更频繁地导致竞争条件错误。

如果能够让应用程序崩溃,首先要查看堆栈跟踪。

在没有优化的情况下分发应用程序没有什么大错,但这只是掩盖了问题。代码中存在一个错误。优化并没有破坏你的代码,是你的代码有问题。

在这里有一个关于调试内存问题的好讨论。第一条规则是必须使用访问器。它们将为你节省很多麻烦,希望你已经在使用。我在我的内存管理规则简短讨论中提供了一些其他的指导。

感谢您的评论。我很感激您的建议。

0