【译】iOS Crash Exception Types

2018-02-28  本文已影响164人  招财小能手

原文地址:https://developer.apple.com/library/content/technotes/tn2151/_index.html#//apple_ref/doc/uid/DTS40008184-CH1-ANALYZING_CRASH_REPORTS

Bad Memory Access [EXC_BAD_ACCESS // SIGSEGV // SIGBUS]

进程试图访问无效内存,或者试图访问超过内存保护等级的内存(比如访问只读内存)。异常子类型区域包含 kern_return_t,用于描述错误和被错误访问的内存地址。

调试 bad memory crash 的 tips:

Abnormal Exit [EXC_CRASH // SIGABRT]

进程非正常退出。最常见的崩溃原因是由于发生了未被捕捉的 OC 或者 C++ 异常,调用了 abort()。

如果在初始化的时候耗时过长,应用扩展会被以这种异常类型终止(watchdog termination)。如果是一个扩展是由于启动时时间太长而被杀掉,那么其异常子类型应该为 LAUNCH_HANG。由于扩展没有 main 函数,所以其的初始化的时间都花费在你的扩展和依赖库的静态构造函数和 +load 函数中。你应该尽可能的推迟这项工作。

Trace Trap [EXC_BREAKPOINT // SIGTRAP]

类似于非正常退出,这种异常的目的是为了给连接的调试器一个机会在特定的时间点来打断一个处在异常中的进程。你可以使用 __builtin_trap() 函数来在自己的代码中触发这个异常。如果没有连接调试器,进程会被终止,并生成一个 crash 报告。

低层级的库(e.g. libdispatch)在遇到致命错误时会捕获进程。关于错误的附加信息会出现在崩溃报告的 Additional Diagnostic Information 区域,或者设备的控制台里。

如果如下的未预期的状况发生在 runtime 时,Swift 代码会终止运行,同时报这种类型的异常:

当这些未预期的情况发生时,查看堆栈看看是哪里发生的问题。额外信息也会记录在设备的控制台里。你应该在崩溃的位置修改代码来处理这种运行时失败。比如,使用 Optional Binding 而不是强制解封一个 optional 值。

Illegal Instruction [EXC_BAD_INSTRUCTION // SIGILL]

进程试图执行一个非法或未定义的指令。进程可能企图通过一个错误配置的函数指针跳去一个无效地址。

在 intel 处理器里,ud2 操作码会造成一个 EXC_BAD_INSTRUCTION 异常,通常用来在调试中捕获进程。在 intel 处理器中的 Swift 代码遇到未预期的状况时会以这种异常类型终止程序。详见 Trace Trap。

Quit [SIGQUIT]

进程能够被另一个有权管理器生命周期的进程的要求下被终止。 SIGQUIT 不代表进程崩溃了,但是很可能确实表现不好。

在 iOS 里,如果键盘扩展程序载入时间太长,就会被主程序退掉。这种情况,堆栈记录里不太可能能够正确指向该负责的代码。更可能的情况,扩展花了很长时间完成了加载,但是在时间限制之前被停止了,此时还有其他代码在执行,当扩展被退出的时候,于是程序在调用栈之中展示的是正在执行的其他代码。你应该好好分析一下这个扩展应用,去理解启动的时候大多数工作在做什么。同时把这些工作移到一个后台线程去执行,或者推迟执行(比如等到扩展程序加载完成)。

Killed [SIGKILL]

进程被系统要求终止。查看 Termination Reason 来理解为何被终止。

Termination Reason 区域包含一个 namespace 和一个 code。以下 code 是专门针对 watchOS 的:

Guarded Resource Violation [EXC_GUARD]

进程违反了被守护资源的保护政策。系统库可能标记特定的文件描述符为 guarded,在这些描述符上正常操作会触发 EXC_GUARD 异常(如果想使用这些文件操作符,系统会使用特定的 guarded 私有 APIs)。这样能够帮助你快速定位一些问题,比如企图关闭一个被系统库打开的文件描述符。例如,如果一个 app 关闭了一个用于返回到 Core Data 存储的 SQLite 文件的文件描述符,那么之后 Core Data 将神秘崩溃。这种 guard 异常让这些问题尽早被注意到,使之更易被调试。

更新版本的 iOS 的崩溃报告在 Exception Subtype 和 Exception Message 中包含 一些造成 EXC_GUARD 异常的人类可阅读详细信息。在 macOS 和老版本的 iOS 中,这些信息被编码到 Exception Code 的第一位中:

Resource Limit [EXC_RESOURCE]

进程超出了资源使用限制。这是 OS 通知进程使用了太多资源。确切的资源被列在 Exception Subtype 区域。如果 Exception Note 区域包含 NON-FATAL CONDITION,那么这个进程并没有被杀死,即便生成了崩溃报告。

一般来说,这是由于线程之间的交流产生的(一般是使用 performSelector:onThread: 或者 dispatch_async),这种在不知不觉中比想象的更频繁。由于触发这种异常的交流发生的如此频繁,这将产生好几个非常相似的堆栈记录,表明了交流的来源。

Other Exception Types

有一些崩溃报告可能包含未命名的异常类型,会使用十六进制的数值打印。如果你收到这种崩溃报告,直接查看 Exception Codes 区域获取更多信息。

注:使用 App 切换器终止一个暂停中的 app 不会产生崩溃日志。一旦一个 app 已经暂停了,那么它可以被 iOS 在任何时候被终止,且不产生任何崩溃日志。

上一篇 下一篇

猜你喜欢

热点阅读