iOS内存泄露检测,很多人会想到使用Instruments。由于学习成本比较高,且专业详细的教程也比较少,所以一般不怎么使用。
MLeaksFinder 是腾讯WeRead团队开源的一款检测 iOS 内存泄漏的框架,其使用非常简单,只需将文件加入项目中,如果有内存泄漏,3秒后自动弹出 alert 来捕捉循环引用。具有无侵入性、
可构建泄漏堆栈、白名单机制等优点。
MLeaksFinder 的基本原理是这样的,当一个 ViewController 被 pop 或 dismiss 之后,我们认为该 ViewController,包括它上面的子 ViewController,及它的 View,View 的 subView 等,都很快会被释放,如果某个 View 或者 ViewController 没释放,我们就认为该对象泄漏了。
具体的做法
为基类 NSObject 添加一个方法 -willDealloc 方法,该方法的作用是,先用一个弱指针指向 self,并在3秒后,通过这个弱指针调用 -assertNotDealloc,而 -assertNotDealloc 主要作用是直接中断言。
UIViewController的分类中,使用 Method Swizzling,hook掉了viewDidDisappear:
,viewWillAppear:
,dismissViewControllerAnimated:completion:
等方法,让他们都执行willDealloc方法,这样,在不入侵开发代码的情况下,为UIViewController添加了检查内存泄露的功能(AOP)
释放前调用这个方法,如果2秒后它被释放成功,weakSelf 就指向 nil,不会调用assertNotDealloc方法
- (BOOL)willDealloc {
__weak id weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[weakSelf assertNotDealloc];
});
return YES;
}
- (void)assertNotDealloc {
NSAssert(NO, @“”);
}
例如
在tableView中的某一个cell,持有了一个block,在block中使用了self.classBlock,在这个控制器被pop后,MLeaksFinder立刻就弹出了弹窗
LessonWithoutJobCell *cell = [tableView dequeueReusableCellWithIdentifier:reusedID1];
if (!cell) {
cell = [[LessonWithoutJobCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reusedID1];
}
cell.model = model;
[cell setEnterBlock:^{
if (self.classBlock) {
self.classBlock(model);
}
}];
return cell;
MLeaksFinder 是如何构建堆栈?
构造堆栈信息的原理就是,递归遍历子对象,然后将父对象 class name 加上子对象 class name,一步步构造出一个 view stack。出现泄漏则直接打印此对象的 view stack 即可。
查找循环引用链
使用的是Facebook 开源的检测循环引用工具 FBRetainCycleDetector,我们知道,很多循环引用是 block 的使用不当造成的。而 FBRetainCycleDetector 最大的技术亮点,正在于如何找出一个 block 的所有强引用对象。对于这个感兴趣的,可以看 facebook 的这篇文章。
添加白名单
#import "NSObject+MemoryLeak.h"
[NSObject addClassNamesToWhitelist:@[@"UIImagePickerController"]];
参考资料:
http://wereadteam.github.io/2016/07/20/MLeaksFinder2/ ([WeRead团队博客])
https://juejin.im/entry/5c064362f265da6165015778
https://www.jianshu.com/p/ccf3014ca6a6(这个比较详细)
iOS的hook是什么意思?
https://www.jianshu.com/p/1113ac4e9ecd
https://www.jianshu.com/p/0eeb3885b2e1