这让我疯了。我刚刚第一次将我的第一个应用程序上传到App Store,当然,现在我的应用程序左右爆炸了。当我使用发布版本配置构建时,我在应用程序上敲了一段可变的时间后随机获得EXC_BAD_ACCESS
。我重新打开Zombies,但问题似乎并没有过度释放变量,因为我没有得到关于向已发布变量发送消息的消息。
错误总是出现在我的代码中的相同位置。看起来我正在尝试保留一个尚未正确初始化的变量。我一点也不知道如何做到这一点。
但这是奇怪的事情:如果我构建调试版本配置,它永远不会崩溃。我整天都可以砰的一声,它坚如磐石。我使用Release配置构建,它会间歇性地崩溃。
查看两种配置中的Build设置,没有太多差异。在调试中,GCC 4.0优化级别为“无”,而在发布时,它是“最快,最小”。如果我将Release中的优化级别切换为“None”,则应用程序会自行运行。有没有人知道我应该寻找什么来解决这个问题?或者,如果我分配没有优化,会发生多少坏事?
更新
荡!我真的需要一个神奇的调试工具来解决内存错误。我在最后一天左右一直在解决这个问题。我添加了一个exercise
方法,可以可靠地生成崩溃并开始查找导致它的代码区域。
应用程序通常会在我执行一种特定类型的操作时第3到第5次崩溃。关于这种类型的操作唯一不同的是我从附件方法返回的值。附件方法通常返回值{0}的NSDecimalNumber
s,但是当我返回具有非整数值的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 :(得分:2)
如果它只是像打开Zombies一样容易,你总能找到你的过度发布......僵尸无法检测到很多这类错误。内存错误没有神奇的调试工具;只有仔细编程(并且有些模式会使这些错误更加罕见,并且在发生这些错误时更容易调试)。
优化的代码可以摆脱许多未经优化的代码中未显示的内容。它确实略微暗示它可能是局部变量而不是ivar,但也许不是。它可能只是时间;速度越快,竞争条件就会越来越频繁。
如果你可以让它崩溃,那么在堆栈跟踪中看一下当然是第一步。
在没有优化的情况下进行分发并没有什么不妥,但它只是掩盖了问题。那里有编码错误。优化不会破坏您的代码。你的代码坏了。
对调试内存问题进行了很好的讨论here。 #1规则是您必须使用访问者。他们会为你节省很多心痛,所以希望你已经这样做了。我在memory management rules的简短讨论中提供了一些其他的指示。
答案 1 :(得分:1)
我建议在编译器上启动警告级别,看看是否弹出任何内容。打开项目设置并启用您可以找到的每个“警告”选项。或者,找到名为其他C标志的项目设置,并添加标记-Wall -Wextra
。
你可以(通常)安全地忽略你会得到很多白噪声,例如有符号/无符号不匹配,可能的精度损失等等。但是,可能会出现一些您绝对不应忽略的关键警告:诸如从没有强制转换的整数制作指针(反之亦然)。如果您不是100%确定可以忽略警告,请修改代码以便警告消失。