更新
升级到 Xcode8之后, 这个库好像没有用了, 具体原因也不详细追究了, 因为 Xcode 自带了强大的 Debug Memory Graph, 直接以关系图的形式来告诉你各个对象的持有关系, 以及出现了泄露时会有紫色的小感叹号出现, 不出现也不意味着没有哟, 所以还需要用这个工具时不时看看现有的存活对象中有没有期望之外的.
下面是一些关键步骤的截图:
如果在警告列表中没有看到任何东西, 先切换到 BuildTime 那里把右下角的警告筛选给关了就会出现了, 个人认为这是 Xcode 的一个 bug...
选中某个泄露对象后会出现持有和它有关系的对象关系图, 如下:
这个例子说我们的 ViewController 被 block 持有了, 点击红圈里面的展开可以看到更多的信息, 具体过程就不详细讲了, 因为这里给到的信息已经足够详细, 再需要一些耐心就可以找出具体的原因了.
!注意: 不要开着 NSZombie 来检测, 不然你会发现一大票的泄露.
新工具简介就到这边了, 下面的老的MLeaksFinder的内容, 已经过时, 不读也罢...
前言
一般来说, iOS的内存泄露检测大多是通过Instruments里面的Leaks. Leaks里面可以看到某各类有多少个实例, 还会指出一些循环引用的图示和泄露点. 虽然看起来很美好, 但是每次实际使用的时候, 多多少少会出现一些问题, 最让人难以忍受的就是明明泄露了但是没有报警.
为了解决这个问题, 在这里介绍一个MLeaksFinder的开源库, 这个库是代码级别的检测view和viewController是否出现内存泄露的情况. 它的优势是只要引入后不侵入现有代码, 正常跑一遍APP, 如果出现泄露, 将会触发断言打印相关日志提醒我们出现了泄露. 缺点也比较明显了, 就是只能检测view和viewController级别的泄露. 不过一般来说也足够用了, 毕竟这是大头.
github地址:https://github.com/Zepo/MLeaksFinde
原理
MLeaksFinder的原理还是很简单的, 它swizzle了NavigationController的Push和Pop相关方法来管理viewController和view的生命周期, 在你Pop掉viewController的时候, 会执行这么一段代码
__weak id weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[weakSelf assertNotDealloc];
});
3秒后执行 [weakSelf assertNotDealloc]; 如果这个时候view和viewController已经释放了, 那么weakSelf应该为nil, 所以将不会触发断言, 否则将会打印日志, 触发断言.
实际操作
为了验证是否真正出现泄漏的情况, 可以在出现断言的时候, 进入Instruments的Leaks来看查看类实例个数, 反复进入目标页面后可以查看目标类的实例情况,例如:
Persistent是当前的实例个数, 如果发现Pop之后没有减少, 就肯定是泄漏了. 这里也吐槽一下Instrument, 这种情况是检测不出来的.
发现泄漏点是第一步, 后面还要看怎么泄漏, 方法还是有很多的, 可以自己查相关页面的代码, 我的操作步骤一般是:
2). 进入到实例页面之后, 再选中实例再点击箭头会出现retain和release的时序列表. 这个时候很卡的话建议暂停运行APP
3). 在这个时序表中查看有没有不该retain但是retain了的函数, 一般只需要看那些单独+1 -1的行, 说明这里的retain和release是没有平衡起来的, 除非是系统代码或者有意为之, 否则都会有一些问题.
4). 发现可疑点之后, 双击进入相关代码, 查看泄露情况, 一般是选择泄露比重最大的那一行代码, 然后进行深入分析.
5). 如果你也曾经出现死活都找不到泄露的位置, 那么时候祭出大杀器--注释代码了.
另外, 对于一些view的泄露, 还是要善用一下Xcode自带的功能, 一般我的操作会是跳到UIImageView或者UILabel的泄漏点选中self, 然后在变量区下面点击那个眼睛, 如下图:
看到里面的内容就能大致猜出出现泄漏的地方了, 一般而言, view单独泄漏的情况还是比较少的, 虽然也出现过, 但是总体而言都是viewController的泄漏连带了view的泄漏.
结语
这个简单的库帮助我找到了很多Instruments没有报警的泄漏点, 个人觉得很好用, 而且引入进来就算忘记移出也没关系, 已经用DEBUG宏包裹起来了, 不会影响到发布.
另外, 有没有同学遇到过前端页面用了-webkit-overflow-scrolling:touch导致出现UIWebOverflowScrollView泄露的啊? 求指导解决.