Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT) 是什么情况?

| Swift , iOS , Xcode , Bug

 

内容概览

  • 前言
  • EXC_BAD_ACCESS 是什么?
  • EXC_BAD_ACCESS 常见解决方法?
    • 启用 Zombies Objects 辅助分析
    • 启用 Analyze 代码分析
    • 启用 Address Sanitizer 进行分析
  • EXC_I386_GPFLT 有解吗?
  • 总结

 

前言

 

我相信大家都曾见过 Xcode 报 EXC_BAD_ACCESS 这个错误,而且网上关于这个错误码的搜索结果不计其数:

既然经常遇到,那咱们就要深入了解一下,看它到底是个什么鬼~

 

EXC_BAD_ACCESS 是什么?

 

如何理解这个错误码?

EXC: 操作系统内核抛出的异常(exception)
BAD ACESS: 不能访问内存

所以,Ficow 用一句话解释,它就是内存访问异常。

 

EXC_BAD_ACCESS 常见解决方法?

 

启用 Zombies Objects 辅助分析

僵尸对象:本来应该已经被释放,但是仍然在内存里的对象。
开启僵尸对象之后,可以有效地帮助 Xcode 分析野指针访问等行为。

如图所示,勾选即可启用:

开启之后,就可以尝试去重现问题,看下 Xcode 会给出什么具体的错误信息。

启用 Analyze 代码分析

如图所示,点击启动即可开始分析:

如果分析工具认为代码有问题,相关的代码及问题就会被罗列在这里:

启用 Address Sanitizer 进行分析

苹果开发者文档 Locate memory corruption issues in your code 部分也详细阐述了 Address Sanitizer 的工作原理和注意事项:

Address Sanitizer 工具用自定义实现替换了 malloc(:) 和 free(:) 函数。 自定义 malloc(:) 函数用特殊的禁区包围请求的内存块,并报告试图访问这些区域的行为。 free(:) 函数将释放的块放入特殊的隔离队列中,并报告试图访问该隔离内存的行为。
Address Sanitizer 不会检测内存泄漏、尝试访问未初始化的内存或整数溢出错误。使用 Instruments 和其他消毒工具查找其他错误。

如果你感兴趣,可以深入了解一下 Address Sanitizer

使用 Address Sanitizer 可以分析以下常见的内存问题:

  1. 对堆、栈和全局变量的越界访问;
  2. 访问释放后的对象;
  3. 访问函数返回后的对象;
  4. 访问作用域后的对象;
  5. 多次释放,无效释放;
  6. 内存泄露;

不过,需要注意的是,开启 Address Sanitizer 通常会使你的程序比未开启时慢1倍。

开启之后,就可以尝试去重现问题,看下 Xcode 会给出什么具体的错误信息。

 

EXC_I386_GPFLT 有解吗?

 

对于 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

评论区(期待你的留言)