iOS内存泄漏检测方法

常见泄漏的点
  • Retain Cycle,Block强引用
  • NSTimer释放不当
  • 第三方提供方法造成的内存泄漏
  • CoreFoundation方式申请的内存,忘记释放

  1. Block引用内存泄漏问题:

[cell setSelectTagCityBlock:^(NSIndexPath *indexPath, NSInteger index){
        [self tableView:_tableViewCityList didSelectRowAtIndexPath:indexPath index:index];
    }];

   利用__weak防止Block循环引用方法:

//创建__weak弱引用,防止强引用互相持有
__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
    //创建局部__strong强引用,防止多线程情况下weakSelf被析构
     __strong __typeof(weakSelf)strongSelf = weakSelf;
    strongSelf.networkReachabilityStatus = status;
    if (strongSelf.networkReachabilityStatusBlock) {
         strongSelf.networkReachabilityStatusBlock(status);
    }
};

weak 本身是可以避免循环引用的问题的,但是其会导致外部对象释放了之后,block 内部也访问不到这个对象的问题,我们可以通过在 block 内部声明一个 strong 的变量来指向 weakObj,使外部对象既能在 block 内部保持住,又能避免循环引用的问题

block 本身无法避免循环引用的问题,但是我们可以通过在 block 内部手动把 blockObj 赋值为 nil 的方式来避免循环引用的问题。另外一点就是 block 修饰的变量在 block 内外都是唯一的,要注意这个特性可能带来的隐患。

  

  2. Timer不被释放引起的内存泄漏:

_timer = [NSTimer timerWithTimeInterval:[refreshTime integerValue]
                                             target:self
                                           selector:@selector(doFSearchDoubleBackNumberRequest:)
                                           userInfo:searchResult
                                            repeats:NO];
            [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
            

Timer 添加到 Runloop 的时候,会被 Runloop 强引用。
Timer 又会有一个对 Target 的强引用。
所以说如果不对Timer进行释放,Timer的targer(self)也一直不会被释放。
有时候我们我们对某个Timer的targer设置了nil。但没设置[timer invalidate]。
其实这个对象还是没被释放的。timer对应的执行方法也一直会在线程中执行。容易造成内存泄露。

注:repeats:NO不会强引用
常规的监测方法
  • Analyze静态分析 (command + shift + b)

    主要分析以下四种问题:

    1、逻辑错误:访问空指针或未初始化的变量等;

    2、内存管理错误:如内存泄漏等;

    3、声明错误:从未使用过的变量;

    4、Api调用错误:未包含使用的库和框架。

    静态分析结果会有警告提示

  

  • Instruments中的Leak动态分析内存泄漏

    product->profile ->leaks 打开工具主窗口

  

  点击暂停,将鼠标移到叉号上面点击锁定,点击下方的“田”字格,选择callTree,

  选择中间的齿轮,选中选项中的 invert Call Tree 和Hide System Libraries。

Call Tree选项说明:
Separate by Thread:按线程分开做分析,这样更容易揪出那些吃资源的问题线程。特别是对于主线程,它要处理和渲染所有的接口数据,一旦受到阻塞,程序必然卡顿或停止响应。
Invert Call Tree:反向输出调用树。把调用层级最深的方法显示在最上面,更容易找到最耗时的操作。
Hide System Libraries:隐藏系统库文件。过滤掉各种系统调用,只显示自己的代码调用。
Flattern Recursion:拼合递归。将同一递归函数产生的多条堆栈(因为递归函数会调用自己)合并为一条。

  双击左边 Call Tree 窗口里的任意一行,查看内存泄漏的代码位置:

  

  • Allocation工具了解内存的分配情况

每次点击generations(是两个时间标记之间所有仍然活着的对象的快照)生成快照,而且 Allocations 会记录从上回内存快照到这次内存快照这个时间段内,新分配的内存信息,数次 push 跟 pop 之后,内存还不断增长,则有内存泄露。

  

参考Link:https://www.jianshu.com/p/9fc2132d09c7

猜你喜欢

转载自www.cnblogs.com/Blueleaf-tech/p/9984558.html