iOS 中应对内存泄漏

instruments 检查内存泄漏

苹果原生支持的工具,在开发模式下调试性能,但无法和自动化,CI进行结合。

  1. 在xcode中对当前项目执行Profile,打开leak模板
  2. 在leak中选择对应的设备和程序,点运行,如下图
iOS 中应对内存泄漏_第1张图片
leak01.png

在导航栏中可以输入关键字筛选数据,在实际使用中,我们可以对一个页面退出后,若该页面中相关内存分配还没清空,这时候就发生内存泄漏了。

AddressSanitizer

使用AddressSanitizer分析内存泄漏。AddressSanitizer开启之后,在debug过程中,如果遇到EXC_BAD_ACCESS的问题,Xcode会自动中断,抛出异常。AddressSanitizer的原理是当程序创建变量分配一段内存时,将此内存后面的一段内存也冻结住,标识为中毒内存。当程序访问到中毒内存时(越界访问),就会抛出异常,并打印出相应log信息。调试者可以根据中断位置和的log信息,识别bug。如果变量释放了,变量所占的内存也会标识为中毒内存,这时候访问这段内存同样会抛出异常(访问已经释放的对象)。


iOS 中应对内存泄漏_第2张图片
实验2.png

下面制造一个访问野指针的场景,array被释放后,继续使用


iOS 中应对内存泄漏_第3张图片
访问野指针.png

此时使用AddressSanitizer,可以看到使用野指针的地方抛出了异常。

iOS 中应对内存泄漏_第4张图片
addressSanitizer00.png

此时复制其地址,在XCode中Debug->Debug Workflow->View Memory,查看该内存的使用情况,可以看到array已经被释放。

iOS 中应对内存泄漏_第5张图片
addressSanitizer.png

NSZombieEnabled

可以定位一些EXC_BAD_ACCESS问题,在对象被错误释放的情况下,可以定位到具体的错误使用被已被释放内存的对象。zombie的原理是用生成僵尸对象来替换dealloc的实现,当对象引用计数为0的时候,将需要dealloc的对象转化为僵尸对象。如果之后再给这个僵尸对象发消息,则抛出异常,并打印出相应的信息
具体的设置,product->edit scheme->argument 下的Environment Variables。添加环境变量,NSZombieEnabled值为YES即可。在XCode8中在edit scheme中diagnositics中勾选Zombie Objects。如下图

iOS 中应对内存泄漏_第6张图片
zombie勾选.png

同上制造访问野指针的场景,看到下图,可以看到有message发给已经被dealloc的对象,导致异常。

iOS 中应对内存泄漏_第7张图片
zombie_结果.png

compiler flags

undefined-trap可以检测出程序中的不明确行为,如数据溢出等。如下图所示当数据发生溢出时,系统会抛出异常。

iOS 中应对内存泄漏_第8张图片
数据溢出.png

All Exceptions

当crash停在main中时,可能是EXC_CRASH(SIGABRT)或EXC_BAD_ACCESS(SIGBUG/SIGSEGV)导致的。可以在全局加断点的方式来查看是哪一行导致了crash。
下面制造一个crash,如下图:

iOS 中应对内存泄漏_第9张图片
crash01.png

此时运行,会报错,如下图:


crash01_result01.png

此时选择All Exception,就可以看到具体哪行crash了

iOS 中应对内存泄漏_第10张图片
all_exception.png
crash_01_result02.png

静态检查

在product中选择Analyze。可以检查出明显没有释放的内存,主要在两种场景中使用,
MRC文件中忘记release或者autorelease,C方式申请内存中忘记释放内存,遗漏了free。
在关闭ARC的情况下,打开product->Analyze,可以看到下图,图中蓝色标记的为有问题的地方。

iOS 中应对内存泄漏_第11张图片
analyze.png

method_exchangeImplementations

使用method_exchangeImplementations接管alloc和dealloc,记录每一次内存分配和地址,再遍历堆区,全局区,栈区的指针变量,进行比较,找出没有指针变量指向的内存地址。(这个好像比较高阶,还没实验成功)

你可能感兴趣的:(iOS 中应对内存泄漏)