iOS 崩溃日志中的异常类型
Posted
技术标签:
【中文标题】iOS 崩溃日志中的异常类型【英文标题】:Exception Types in iOS crash logs 【发布时间】:2011-11-18 18:52:28 【问题描述】:自从我开始学习 ios 开发以来,我已经看到了几种不同类型的崩溃日志。
我知道: 异常类型:EXC_BAD_ACCESS (SIGSEGV)表示我们正在访问已释放的对象。
但不知道:异常类型:EXC_BAD_ACCESS (SIGBUS)异常类型:EXC_CRASH (SIGABRT)异常类型:EXC_BREAKPOINT (SIGTRAP)
你知道 iOS 崩溃日志中有多少个异常类型,它们是什么意思吗?
【问题讨论】:
【参考方案1】:我知道:异常类型:EXC_BAD_ACCESS (SIGSEGV) 表示我们正在访问已释放的对象。
没有。
SIGSEGV 是分段错误,这意味着您正在尝试访问无效的内存地址。
那些异常(实际上它们是信号)与 Objective-C 无关,而是与 C 相关。 所以你可以在没有 Objective-C 对象的情况下得到这样的异常。
请注意,信号不是异常,这意味着您无法使用 @try
和 @catch
块捕获它们。
您可以使用signal
和sigaction
函数设置信号处理程序。请记住一些信号,例如 SIGABRT 不能被阻止。
如果您想了解更多信息,可以查看Wikipedia 信号页面。
也就是说,继续:
SIGSEGV(分段错误)
访问无效的内存地址。该地址存在,但您的程序无权访问它。
SIGBUS(总线错误)
访问无效的内存地址。地址不存在,或者对齐无效。
SIGFPE(浮点异常)
算术运算无效。可以与整数运算相关,尽管有名称。
SIGPIPE
管道破裂。
SIGILL
非法的处理器指令。
SIGTRAP
调试器相关
SIGABRT
程序崩溃,与前面的信号之一无关。
【讨论】:
SIGTRAP 与调试器无关。根据规范,当出现异常时会发生这种情况,如果应用程序在调试器中运行,则会触发调试器断点。如果它没有在调试器中运行,它就会终止。在 Swift 中,它要么试图解开一个 nil 的可选项,要么是一个无效的强制转换。【参考方案2】:SIGSEGV 字面意思是您正在访问一个不属于您的地址。因此,您不一定要访问已发布的对象;您可能正在访问一个从未存在过的对象,例如:
UIView *view; // uninitialised, could point to anything
[view setFrame:someFrame];
甚至只是在 C 级的非对象内容中出错,例如:
int array[100];
array[1000] = 23; // out-of-bounds access
SIGBUS 与 SIGSEGV 非常相似,区别在于硬件级别(通常是尝试访问确实存在但您不拥有的地址和尝试访问没有任何内容的地址之间的区别它,但这不是一个严格的定义),但通常与相同类型的错误相关联,尽管 SIGBUS 更可能与未初始化的变量有关而不是 SIGSEGV。
如果您试图映射到您可能在 Objective-C 中犯的错误,您可能只想将 SIGSEGV 和 SIGBUS 一起解读为“我无权进行的内存访问”。
SIGABRT 是一个试图自行中止的程序,因此它通常意味着某种内部一致性检查失败。例如,如果您尝试释放相同的内存两次,或者 - 在 Cocoa 级别 - 如果您的 raise
NSException
未被捕获,则会引发 SIGABRT。如果您收到 SIGABRT,则说明您做错了,系统软件可以检测到(与硬件中出现的 SEGV 和 BUS 不同)。
SIGTRAP 是从程序到调试器的调用。有趣的是,当您做一些可以在软件中检测到但与环境而不是您的特定代码相关的错误时,Apple 似乎会使用这些。因此,例如,您调用存在于您构建的 SDK 中但不在您正在运行的设备上的 C 函数(例如,当您针对具有较低部署目标的最新 SDK 构建时),或使用一个对象。
【讨论】:
提供的样本不会在 xcode6.1 中引发异常 有了 ARC,第一个样本现在是明确合法的;view
被隐式初始化为 nil
并且消息传递始终是安全的。尝试将其设置为随机地址。我现在在 iPad 上;当我使用真正的键盘时将进行编辑。【参考方案3】:
这些消息来自 gdb,它们不是 Objective-C 独有的。
要获取有关信号的信息,您只需在调试器控制台this is an example output 中输入info signals
。很抱歉没有在这里发布,但控制台输出的格式很糟糕。
Source and more info about signals
【讨论】:
【参考方案4】:我最近研究了这个主题领域,这是我的总结:
EXC_BAD_ACCESS (SIGSEGV)
或
EXC_BAD_ACCESS (SIGBUS)
我们的程序很可能试图访问一个错误的内存位置或地址是好的,但我们没有访问它的权限。由于内存压力,内存可能已被释放。
EXC_BREAKPOINT (SIGTRAP)
这是由于NSException
被提出(可能由图书馆代表我们)或_NSLockError
或objc_exception_throw
被调用。例如,这可能是 Swift 环境检测到异常,例如强制解开 nil 可选。
EXC_BAD_INSTRUCTION (SIGILL)
这是程序代码本身有问题的时候,而不是它可能正在访问的内存。这在 iOS 设备上应该很少见;可能是编译器或优化器错误,或者错误的手写汇编代码。在模拟器上,情况就不同了,因为使用未定义的操作码是 Swift 运行时用来停止访问僵尸对象(解除分配的对象)的一种技术。
EXC_GUARD
这是程序关闭受保护的文件描述符的时候。一个例子是系统使用的 SQLite 数据库。
【讨论】:
以上是关于iOS 崩溃日志中的异常类型的主要内容,如果未能解决你的问题,请参考以下文章