内容字号:默认大号超大号

段落设置:段首缩进取消段首缩进

字体设置:切换到微软雅黑切换到宋体

iOS性能优化之内存泄露检测

2018-12-05 20:41 出处:清屏网 人气: 评论(0

iOS性能优化是一个比较复杂的问题,其中之一就是内存泄露检测,很多人会第一时间想到使用Instruments。由于学习成本比较高,专业详细的教程也比较少,在学习了基本介绍后就望而生畏了。今天浏览了微信阅读团队的技术博客,发现了一个非常友好的内存泄露检测库 MLeaksFinder

MLeaksFinder

简单介绍一下MLeaksFinder。

官方解释:

具体的方法是,为基类 NSObject 添加一个方法 -willDealloc 方法,该方法的作用是,先用一个弱指针指向 self,并在一小段时间(3秒)后,通过这个弱指针调用 -assertNotDealloc,而 -assertNotDealloc 主要作用是直接中断言。

核心代码:

- (BOOL)willDealloc {
    __weak id weakSelf = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [weakSelf assertNotDealloc];
    });
    return YES;
}

- (void)assertNotDealloc {
     NSAssert(NO, @“”);
}

这样,当我们认为某个对象应该要被释放了,在释放前调用这个方法,如果3秒后它被释放成功,weakSelf 就指向 nil,不会调用到 -assertNotDealloc 方法,也就不会中断言,如果它没被释放(泄露了),-assertNotDealloc 就会被调用中断言。这样,当一个 UIViewController 被 pop 或 dismiss 时(我们认为它应该要被释放了),我们遍历该 UIViewController 上的所有 view,依次调 -willDealloc,若3秒后没被释放,就会中断言。

例如在UIViewController的分类中,使用 Method Swizzling ,hook掉了 viewDidDisappear:viewWillAppear:dismissViewControllerAnimated:completion: 等方法,让他们都执行willDealloc方法,这样,在不入侵开发代码的情况下,为UIViewController添加了检查内存泄露的功能(AOP)。

安装

安装非常简单,直接在Podfile中添加 pod 'MLeaksFinder' ,你不需要在任何文件中引入头文件,执行 pod install 后,直接构建或者run一下就好了。

案例

在iOS中,比较常见的内存泄露场景就是循环引用。作为一个iOS工程师,应该时刻警惕循环引用带来的问题。然而在赶工或者稍有不慎的情况下,还是会出现一些有问题的代码。

对于Xcode来说,编译器会对编写代码中明显的循环引用进行提示,比如对于self.property持有的block中,使用self,Xcode就会显示警告。但是,对于以下代码,Xcode就不会警告:

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;

在tableView中的某一个cell,持有了一个block,在block中使用了self.classBlock,乍一看好像没有问题啊。

真的没有问题吗?

在这个控制器被pop后,MLeaksFinder立刻就弹出了弹窗

IMG_6481.PNG

点击Retain Cycle

IMG_6479.PNG

仔细想想,真的是出现循环引用。首先是self引用了tableView,tableView引用了cell,cell中的block引用了self,这样,在控制器被pop之后,这个view还存在着强引用,这样它的内存就得不到释放,这样就造成了循环引用,经历频繁的push和pop操作后,内存将会暴增。其实这是一个很低级的bug了,但是稍不注意,就被忽略了。

既然发现了问题,解决循环引用就非常简单了。在cell的block外面,把self定义为weak类型,打破循环引用:

······
__weak typeof(self) weakSelf = self;
······
//把block中的self换成weakSelf即可
[cell setEnterBlock:^{
    if (weakSelf.classBlock) {
        weakSelf.classBlock(model);
    }
}];

至此,MLeaksFinder的简单使用就介绍完了,真的十分简单就找到了一些潜在的问题,对于工程几乎0入侵,强烈推荐使用。

分享给小伙伴们:
本文标签: 内存泄露iOS性能优化

相关文章

发表评论愿您的每句评论,都能给大家的生活添色彩,带来共鸣,带来思索,带来快乐。

CopyRight © 2015-2016 QingPingShan.com , All Rights Reserved.

清屏网 版权所有 豫ICP备15026204号