我相信大家都曾见过 Xcode 报 EXC_BAD_ACCESS
这个错误,而且网上关于这个错误码的搜索结果不计其数:
既然经常遇到,那咱们就要深入了解一下,看它到底是个什么鬼~
如何理解这个错误码?
EXC: 操作系统内核抛出的异常(exception)
BAD ACESS: 不能访问内存
所以,Ficow 用一句话解释,它就是内存访问异常。
僵尸对象:本来应该已经被释放,但是仍然在内存里的对象。
开启僵尸对象之后,可以有效地帮助 Xcode 分析野指针访问等行为。
如图所示,勾选即可启用:
开启之后,就可以尝试去重现问题,看下 Xcode 会给出什么具体的错误信息。
如图所示,点击启动即可开始分析:
如果分析工具认为代码有问题,相关的代码及问题就会被罗列在这里:
苹果开发者文档 Locate memory corruption issues in your code 部分也详细阐述了 Address Sanitizer 的工作原理和注意事项:
Address Sanitizer 工具用自定义实现替换了 malloc(:) 和 free(:) 函数。 自定义 malloc(:) 函数用特殊的禁区包围请求的内存块,并报告试图访问这些区域的行为。 free(:) 函数将释放的块放入特殊的隔离队列中,并报告试图访问该隔离内存的行为。
Address Sanitizer 不会检测内存泄漏、尝试访问未初始化的内存或整数溢出错误。使用 Instruments 和其他消毒工具查找其他错误。
如果你感兴趣,可以深入了解一下 Address Sanitizer。
使用 Address Sanitizer 可以分析以下常见的内存问题:
- 对堆、栈和全局变量的越界访问;
- 访问释放后的对象;
- 访问函数返回后的对象;
- 访问作用域后的对象;
- 多次释放,无效释放;
- 内存泄露;
不过,需要注意的是,开启 Address Sanitizer
通常会使你的程序比未开启时慢1倍。
开启之后,就可以尝试去重现问题,看下 Xcode 会给出什么具体的错误信息。
对于 EXC_BAD_ACCESS
这一类内存访问错误,EXC_I386_GPFLT
是一种比较难处理的错误场景。
即使有牛人做了解答,但是这种错误的成因也很难简单几句话说清楚。
有很多人在使用 Alamofire 的时候也遇到过,维护该库的大神认为是 Swift 版本和 Xcode 编译优化选项导致的问题:
EXC_BAD_ACCESS (code=EXC_I386_GPFLT) on authenticate() method #3148)
Ficow 在调用一个自定义的协议类型实例的时候也遇到了这个问题:
相关的类型定义和实例初始化代码如图所示,其实并没有涉及到什么特别的用法:
然而,在调用点直接访问 AppEventTracker.shared
这个被注入的单例,不会有同样的错误发生。
也就是说,通过注入的 eventTracker
引用(以协议类型定义)去访问同一个地址,就会导致 EXC_I386_GPFLT
这个错误。
那么,为什么直接用单例去调用就没问题,用协议类型的引用去调用就会出故障?
好吧,Ficow百思不得其解,欢迎大神不吝赐教~
既然没有办法,那就把所有可能的办法都试试,俗话说暴力出奇迹嘛。
于是 Ficow 把上文提到的方法都试了一遍。。。
然而,就在开启了 Address Sanitizer
之后, EXC_I386_GPFLT
这个错误就消失了,而且 Xcode 并没有再检测到其他任何内存访问错误!!! 😄 有点想爆粗~
这不禁让我怀疑,这真的就是 Swift 版本的问题。
我会尝试切换 Swift 版本来解决这个问题,并在本文发布后续的测试结果。
如果你也遇到了类似的问题,可以考虑先试试上面的这些方法。
只要是代码就一定有可能出bug,不要怀疑苹果的工程师,他们也是会写bug的呢~
我们作为一名普通的开发者,遇到这些诡异的错误,最可行的做法往往就是广泛地搜集前人的解决办法并不断地尝试。
如果你有更好的办法, 欢迎不吝赐教呀~
参考内容:
What Is EXC_BAD_ACCESS and How to Debug It
EXC_BAD_ACCESS crash error: Understanding and solving it
Address Sanitizer
What’s the meaning of exception code “EXC_I386_GPFLT”?
Diagnosing memory, thread, and crash issues early
觉得不错?点个赞呗~
本文链接:Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT) 是什么情况?
转载声明:本站文章如无特别说明,皆为原创。转载请注明:Ficow Shen's Blog