Instruments之Leaks

1. 介绍

1. 进程

进程是系统资源分配的最小单位

进程结构

Instruments之Leaks_第1张图片
企业微信截图_0f91f1d2-0c55-4042-b635-96812a59642e.png

进程通信

pipe管道
fifo有名管道
内存共享映射
Unix Domain Socket
Socket(TCP/UDP)

内存地址

32位系统和 64位系统的区别

2. 线程

线程是CPU调度的最小单位

3. 内存泄露

内存泄露指当一个对象或变量在使用完成后没有释放掉, 这个对象一直占用着这部分内存, 直到应用停止.

4. 内存溢出

指程序申请内存时,没有足够的内存空间使用
两种情况
栈溢出,堆溢出

2. iOS内存管理原理

Objective_C 有3种内存管理方法, 它们分别是

  • MRR (Manual Retain Release, 手动保持释放)
  • ARC(Automatic Reference Counting, 自动引用计数)
  • GC(Garbage Collection, 垃圾收集)

1 MRR
① 也称为 MRC(Manual Reference Counting, 手动引用计数)
② 由程序员自己负责管理对象生命周期,负责对象的创建和销毁.

2 ARC
① 采用和 MRR 一样的内存引用计数管理方法。
② 在编译时会在适合的位置插入对象内存释放, (如 release, autorelease, 和 retain 等),
③ 程序员不用关心对象释放的问题, 苹果推荐在新项目中使用 ARC, 但在 iOS5之前的系统中不能采用 ARC.

3 GC
① 在Objective_C2.0之后, 内存管理出现了类似于 Java 和 C#的内存垃圾收集技术, 但是垃圾收集与 ARC 一直运行, 垃圾收集是后台有一个线程负责检查已经不再使用的对象,然后释放之.
② 由于后台有一个线程一直运行, 一次会严重影响性能, 这也是 Java 和 C#程序的运行速度无法超越 C++的主要原因.
③ GC 技术不能应用于 iOS 开发, 只能应用于Mac OS X 开发.

小结:
从上面的介绍可知:
① iOS 采用 MRR 和 ARC 这两种方式, ARC 是苹果推荐的方式.
② MRR 方式相对比较原始, 对于程序员的能力要求很高, 但是它很灵活, 方便, 很不容易驾驭好.

3. leaks界面介绍

Instruments之Leaks_第2张图片
image

在 instruments 中,虽然选择了 Leaks 模板,但默认情况下也会添加 Allocations 模板.基本上凡是内存分析都会使用 Allocations 模板, 它可以监控内存分布情况。
① 选中 Allocations 模板,(图1区域),右边的3区域会显示随着时间的变化内存使用的折线图,同时在4区域会显示内存使用的详细信息,以及对象分配情况.
② 点击 Leaks 模板(图中2区域), 可以查看内存泄露情况。如果在3区域有 红X 出现, 则有内存泄露, 4区域则会显示泄露的对象.

用leaks进行监测

点击泄露对象可以在(下图)看到它们的内存地址, 占用字节, 所属框架和响应方法等信息.打开扩展视图, 可以看到右边的跟踪堆栈信息


Instruments之Leaks_第3张图片
image

监测结果的分析

Instruments之Leaks_第4张图片
image

Allocations—内存分配版面的介绍

Allocations是检测程序运行过程中的内存分配情况的,也需要同时运行着程序。界面情况如下:


Instruments之Leaks_第5张图片
image

Instruments之Leaks_第6张图片
image

双击某一个方法,同样会跳转到代码里,会有每一句代码对应的内存分配情况,根据这些信息,可以对程序里不同代码的内存占用情况有一些认识,并进行针对性的优化。

4. 具体使用

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

第一步

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


image

第二步

然后看看Call Tree,因为Call Tree会给我们大概的位置,有时候会给我们精确的位置,不过要看运气了。
然后,再右面选择Invert Call Tree和Hide System Library

Instruments之Leaks_第7张图片
image

然后双击 上文图片中的任意一行,就会跳到代码处内存泄漏的地方(事实上,到这步,很多内存泄漏的问题都会被发现),当然也有一些泄露还是看不出来的.
第三步
然后我们选择对ARC调试很有用的一个部分Circles & Roots,通过这个我们可以看到详细的ARC引用计数过程。然后,我们看到如下图
小的红色矩形点击可以看到引用计数的详细信息(ARC 就是自动引用计数,计数为0,则对象会被释放)
大的红色矩形可以绘制对象引用环的图,这里如果是我们自己的东西,就能看出来各个对象之间的引用.
Instruments之Leaks_第8张图片
image

如果这里没有引用环的图. 首先我们找一下我们自定义的对象,正常完成任务这个对就应该释放的. 为了确认这个对象有没有释放, 可以重写 dealloc 方法, 在此方法中 log 释放信号, 看看是否被释放.

如果这里就是没有释放,我们可以点击这儿对象后的箭头详细的看下, 这个对象的引用计数变化如图.

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


    Instruments之Leaks_第9张图片
    image

    我们选择Unpaired 和 ByGroup,看到如图


    Instruments之Leaks_第10张图片
    image

第四步

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


Instruments之Leaks_第11张图片
image

再继续看,download start 标号6和8是对应的,继续排除问题出现在这里(当然问题不可能出现在这里,这是系统的API,一定会释放,就是简单教大家如何看)


Instruments之Leaks_第12张图片
image

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

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


Instruments之Leaks_第13张图片
image

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

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

看下文档,发现了这个地方


Instruments之Leaks_第14张图片
image

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

  -(void)setOperationFinished
  {
   [self.session invalidateAndCancel];
   }

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

5. 总结

其实大多数问题在双击上文的代码部分就可以解决了,少数问题需要详细的分析ARC引用过程。
事实上,内存泄露是及其复杂的问题, 工具使用是一方面, 经验是另一方面. 提高经验, 然后借助工具才能解决内存泄露的根本.

6. 建议

如果我们未发现表示内存泄露的红 X, 但是我们想进一步评估某个对象对于内存的应用, 可以看看 Allocations 模板的折线图. 反复执行从创建对象 -> 销毁对象 这个过程, 如果总占用内存数会随之增加, 这说明这个对象没有释放, 有些时候虽然占用的内存不是很严重, 但是也会增加占用内存, 因此必须释放这个对象.

提示

有些情况下, 对象没有释放是无法检测到的,反复测试内存占用也没有明显的增加, 这时最好在配置比较低的设备上测试一下, 如果问题依然, 可以不用释放对象. 但是从编程习惯上讲, 我们应该释放该对象.

你可能感兴趣的:(Instruments之Leaks)