iOS 内存泄漏检测

【YFMemoryLeakDetector】人人都能理解的 iOS 内存泄露检测工具类

背景

即使到今天,iOS 应用的内存泄露检测,仍然是一个很重要的主题。我在一年前,项目中随手写过一个简单的工具类,当时的确解决了大问题。视图和控制器相关的内存泄露,几乎都不存在了。后来想着一直就那个工具,写一篇文章,不过一直没有写。

时过境迁,今天在网上搜了下 “iOS 内存泄露检测”,各种讨论技术文章,有点头大。我忍不住看了下自己当时的代码,突然感觉自己的思路好特别,好有创意。我真的就是在“创建”时把数据记录到一个字典里,在“释放”时,从字典里移出对象;所谓的检测,其实就是打印那个字典,仍然在字典中的很有可能就是泄露喽。

当然,还是有一些技术细节的。我把旧代码适度拆分整理为一个开源库了,取名为 YFMemoryLeakDetector。本篇,将着重讲述简洁之下,可能不易察觉的一些考量。

注意:这个库,相当程度上是为当时的项目量身定制的,你可能需要适当修改,才能在自己的项目中真正发挥出它的力量。

核心技术分析

AOP 机制,借助 Aspects 库实现

Aspects 这个库的基本用法,我专门说过,大家可以参考 Aspects– iOS的AOP面向切面编程的库。当然,用黑魔法直接操作运行时,也是很酷的。不过我当时的确是因为偷懒,才用的 Aspects。一直到现在,我依然觉得,它可能比黑魔法更可靠些。

在字典中直接存储指针地址,而不是直接存储对象自身

存储指针地址的好处是,就是不会因为存储本身影响对象的引用计数。当然,指针地址本身,在 OC 中,其实就是对象自身。而要想得到存地址,不存对象的效果,就要祭出整个工具库的灵魂函数:

将对象转换为 NSValue,直接以 NSValue 为键,来标记对象。这句代码,是整个机制的灵魂所在,也是比其他类似的内存泄露分析库更简洁的重要原因之一。我当时也是搜遍的整个网络,才知道自己要的究竟是什么。

另外,还有一点必须提一下, NSValue 是可以在反向转换为 oc 对象的,这有利于你在拿到工具库提供的泄露信息后,进一步定位和分析问题:

对控制器和视图,采用不同的拦截策略

  • 对象销毁,统一拦截的是 dealloc。现在网上的很多策略,基本也是这样。
  • 对象创建,对于视图,拦截的是 willMoveToSuperview: ;对于控制器拦截的是 viewDidLoad 。直到现在,我依然以为,没有调用过这两个方法的视图或控制器对象,本身没有多大的拦截价值。当然,这依然因项目而异。作为一个工具类,只要它能解决大多数场景下的问题,我觉得就可以了。

load 时,自动开启监测

所以,你只要把工具库源码拖拽到项目中,不需要任何修改,就可以自动监测内存泄露情况了。然后在需要的地方,在合适的时候,去读取 YFMemoryLeakDetector 的单例属性,分析结果即可。当然,这是我今天重构优化过的版本。原来是需要手动初始化的,好 Low,当时写的!

“见码如晤”

YFMemoryLeakDetector.h 头文件部分,主要简化为暴露了存储可能有内存泄露情况的视图和控制器的字典属性;同时提供了一个单例方法,以便于具体分析和操作内存分析情况。

YFMemoryLeakDetector.m 实现,借助于 AspectsvalueWithPointer: 代码大大简化。

使用示例:

这里展示一个基于工具类,二次分析的示例:

参考文章

  • YFMemoryLeakDetector 源码
  • Aspects– iOS的AOP面向切面编程的库
  • MLeaksFinder 新特性
  • MLeaksFinder:精准 iOS 内存泄露检测工具
  • iOS内存泄漏自动检测工具PLeakSniffer

你可能感兴趣的:(iOS 内存泄漏检测)