使用 Instruments 检测内存泄漏

3,591 阅读2分钟

内存管理是 iOS 里一大重要内容,经历过 MRC 时代的开发者或多或少都被引用计数折磨过,后来苹果推出了 ARC (Automatic Reference Counting),这一技术大大减轻了内存管理的工作量,也降低了因内存管理而出错的概率。但在 ARC 下还是有一些场景会导致内存泄漏,例如循环引用、强引用不再使用的对象。

Instruments Leaks

我写了一个 Demo 来进行下面的演示,列举了 3 种内存泄漏的场景,页面截图如下所示:

  • Strong reference 是用一个数组强引用了一个 ViewController,导致这个 ViewController 退出 navigation stack 后还被强引用引起内存泄漏
  • Block retain cycle 就是常见的 block 导致的循环引用
  • NSTimer retain cycle 是常见的 NSTimer 导致的循环引用

要检测内存泄漏我们首先想到的是用 Instruments 的 Leaks 来检测,对以上 3 种情形分别不断 push、pop 后的结果如下所示:

Strong reference:

Strong normal:

Block retain cycle:

Block normal:

Timer retain cycle:

Timer normal:

Leaks 里还有一个选项 Cycles & Roots 能够分析出有循环引用的地方,如下图所示:

通过以上截图我们发现只有 block 导致的循环引用能够被 Leaks 检测出来,但是总的内存使用情况只增不减肯定是有问题的,下面我们使用 Allocations 进行更具体的分析。

Instruments Allocations

我们选择 Allocations 重新开始分析,和上面一样不断进行 push、pop 操作,结果如下图所示:

再对比没有内存泄漏的情况:

通过以上对比我们可以看出正常情况下 push 再 pop 后对应的 ViewController 就被释放了,Total 这一栏里也就不会被列出;而有内存泄漏的类会被列出,这样我们就找出了具体的类,然后就可以针对这个类的使用情况再深入排查可能会出现内存泄漏的地方。

Record reference counts

如果要更进一步查看某一个类的引用计数情况,我们可以打开 Record reference counts,具体操作如下图所示:

打开这个选项后我们再进行前面的操作,结果如下图所示:

总结

虽然使用了 ARC 后能够大大避免内存泄漏的出现,但还是会有一些场景会导致内存泄漏,上述例子里的场景都还是比较常见比较容易避免的,在调用链长的时候一些循环引用就比较难被发现了,因此我们在开发完一个功能模块后使用 Instruments 系统的检测一遍是比较好的习惯。

大家也可以下载这个 Demo 用 Instruments 实际操作体验一遍,enjoy~