Instrument调试内存泄漏-leaks

原创Blog,转载请注明出处
blog.csdn.net/hello_hwc

欢迎关注我的iOS SDK详解专栏
blog.csdn.net/column/manage.html?alias=huangwenchen-ios-sdk

前言:计划是7月份更新Instrument以及调试相关的博客,不过今天刚好遇到个内存泄漏的问题。五月份的数据持久化部分还有三篇左右没更新,六月份集中在多线程开发上。所以这里就简单写一下Instrument中leaks使用吧。

如何打开Leaks

XCode - Open Development Tool - Instruments
Instrument调试内存泄漏-leaks_第1张图片

打开后会看到很多工具
Instrument调试内存泄漏-leaks_第2张图片

选择 leaks打开
Instrument调试内存泄漏-leaks_第3张图片

  1. Allocations纪录了内存分配,用来优化内存使用的
  2. Leaks用来分析内存泄漏。ARC中引起的内存泄漏原因就是引用环。

然后我们运行下一个小工程,这个工程是接下来要更新的一个异步网络下载tableview图片的前期雏形。

这里要提到的是,我的博客写了这么多篇了,还是没有涉及到好的开源库,这部分后续我会写的。毕竟实际开发的过程中对开源库的选择也很重要,而且会大大提高效率。但是,我希望的是先把基础掌握好,这决定了理解的深度。

内存泄漏的工程下载
看下效果图

乍一看还不错啊,tableview非常流畅,图片能够惰性下载(cell屏幕上再下载),这也是我想要的雏形。可是,好奇的用leaks分析一下

我擦
Instrument调试内存泄漏-leaks_第4张图片

然后,我们打开leaks,看看错误出现在哪

先选择Leaks和Leaks by Backtrace.这里可以看到那些对象内存泄漏了,泄漏了多少,这个就是简单看看,没有太多调试意义。

然后看看Call Tree,因为Call Tree会给我们大概的位置,有时候会给我们精确的位置,不过要看运气了。

然后,再又面选择Invert Call Tree和Hide System Library
Instrument调试内存泄漏-leaks_第5张图片

然后,我们就知道大概内存泄漏的位置在NSOperation的子类这里了。

然后双击 上文图片中的任意一行,就会跳到代码处内存泄漏的地方(事实上,到这步,很多内存泄漏的问题都会被发现)

然后我们选择对ARC调试很有用的一个部分Circles & Roots,通过这个我们可以看到详细的ARC引用计数过程。
点击Leaks图标可以选择

然后,我们看到如图

  • 小的红圈点击可以看到引用计数的详细信息(ARC 就是自动引用计数,计数为0,则对象会被释放)
  • 大的红圈可以绘制对象引用环的图,不过这里我们很不幸,没有直观的绘图出来。

然后,首先我们找一下我们自定义的对象,发现了DownloadImageOperation这个对象,这个对象是继承自NSOperation,正常在任务完成后就应该释放的。看来没有释放。为了确认,在DownloadImageOperation最后加上log代码,看看是否被释放

-(void)dealloc{ NSLog(@"dealloc"); }

再运行下程序,果然没有被释放,这里肯定有问题。

最后,我们在点击类似上图的小红圈中的剪头,详细的看下,这个对象的引用计数变化如图
这里

  • All 表示所有的引用计数变化
  • Unpaired表示那些为成对的变化(成对就是leaks识别出了对应的+1,-1)
  • By Group会把相关的变化分成一组,ByTime会按照顺序列出引用计数变化

我们选择Unpaired 和 ByGroup,看到如图
Instrument调试内存泄漏-leaks_第6张图片

按照顺序看(最左边的标号)

  • 4 这里,引用计数是一,这是正确的,因为到这里正常就是应该是OperationQueue保存一个Operation的引用。
    于是,我们把正常的划掉

  • 再继续看,download start 标号6和8是对应的,继续排除问题出现在这里(当然问题不可能出现在这里,这是系统的API,一定会释放,就是简单教大家如何看)
    Instrument调试内存泄漏-leaks_第7张图片

再看看,+1的还剩下标号7 和 11,7 是正常的为Operation分配线程,应当会+1,而11就是我们的问题所在了(大部分Delegate都不会使引用+1)。
我们再看下文档

@property(readonly, retain) id< NSURLSessionDelegate > delegate

原来这个代理是retain啊,不是assign或者weak。所以形成了这样的引用环。

那么怎么办呢?有问题下看文档,我们看到图片中引起引用计数加一的是

+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(id<NSURLSessionDelegate>)delegate delegateQueue:(NSOperationQueue *)queue:

看下文档,发现了这个地方
Instrument调试内存泄漏-leaks_第8张图片

于是,我们要手动的去断开强引用,于是,我们手动去断开

-(void)setOperationFinished{
    [self.session invalidateAndCancel];
    [self willChangeValueForKey:@"isFinished"];
    [self willChangeValueForKey:@"isExecuting"];

    executing = NO;
    finished = YES;

    [self didChangeValueForKey:@"isExecuting"];
    [self didChangeValueForKey:@"isFinished"];

}

再运行下看看,能够正常的Dealloc了

2015-06-05 10:28:36.814 AsyncImageTableviewDemo[1245:83664] dealloc
2015-06-05 10:28:36.954 AsyncImageTableviewDemo[1245:83664] dealloc

用leaks分析,也没有内存泄漏了

总结:其实大多数问题在双击上文的代码部分就可以解决了,少数问题需要详细的分析ARC引用过程。

你可能感兴趣的:(ios,调试,内存泄漏,leaks,instrument)