了解:在苹果没有出ARC(自动内存管理机制)时,iOS开发攻城狮几乎有一半的开发时间都消耗在怎么管理内存上后来苹果人性化推出了ARC,虽然在很大程度上帮助我们开发者节省了精力和时间。但是我们在开发过程中,由于种种原因,还是会出现内存泄漏的问题。
内存泄漏是一个很严重的问题,我们先了解一下xcode7自带的Instruments中的Leaks如何检测我们的程序中内存泄漏以及定位内存泄漏代码(Leaks分析内存泄漏并不能把所有的内存泄漏问题查出来,有的内存泄漏时在运行时,用户操作时才会产生的)
简介内存管理:
- Object-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开发
内存泄漏
- 内存泄漏指当一个对象或变量在使用完成后没有释放掉,这个对象一直占用这部分的内存,直到应用停止
- 这种没有释放掉的对象多了内存就会耗尽,其他应用就无法运行
- 内存泄漏在C++,C和Objective-C的MRR中是比较普遍的问题
- 从理论上讲,内存泄漏是由对象或者变量没有释放引起的,但实践证明并非所有的未释放的对象或变量都会导致内存泄漏,这与硬件环境和操作系统、系统环境有关
- 内存泄漏导致我们软件在运行过程中占用越来越多的内存,占有资源却又得不到及时清理,会导致我们程序效率越来越低,反应慢,会影响我们用户体验,失去市场的竞争能力
iOS中查找漏点的工具
- 在xcode中,共提供两种工具帮助查找泄漏点,
- 1> Analyze
- 学名:静态分析工具
- 查找:可以通过
product -> Analyze
菜单项启动 - 快捷键
CMD + Shift + b
- Analyze主要分析一下四种问题
- 逻辑错误:访问空指针或为初始化的变量等;
- 内存管理错误:如内存泄漏等;
- 声明错误:从未使用过的变量
- Api调用错误:未包含使用库和框架
- 2> Instruments
- 学名:动态分析工具
- 查找:
product -> profile
菜单项启动 - 快捷键
CMD + i
- 简介:它有很多跟跟踪模块可以动态分析和跟踪内存,CPU和文件系统
- 1> Analyze
两种工具查找漏点版本的介绍
- 1> 结合使用-思路分析:
- 先使用Analyze静态分析查找可疑泄漏点,在用Instruments动态分析中的Leaks和Allocations跟踪板块进行动态跟踪分析,确认这些点是否泄漏,或者是否存有新的泄漏点出现等
- 2>使用 静态检测内存泄漏问题 Analyze
-
在Analyze静态分析结果中,凡是有图标出现的行都是工具发现的疑似泄漏点
-
点击疑似泄漏点行末尾的分叉图标,会展开分析结果
-
检测完成时的效果图如下:
- 小结:
- 这里使用Analyze静态分析查找出来的泄漏点,称之为“可疑泄漏点”,之所以称之为“可疑泄漏点”,是因为这些点未必一定泄漏,确认这些点是否泄漏,还要通过Instruments动态分析工具的Leaks和Allocations跟踪模版,Analyze静态分析只是一个理论上的预测过程
- 3> 动态监测Instruments的Leaks
- 1)CMD + i 打开
-
2)打开页面的介绍:
- 在instruments中,虽然选择了Leaks模版,但默认情况下也会添加Allocations模版,基本上凡是内存分析都会使用Allocations模版,它可以监控内存分布情况
- a. 选中Allocations模版,(图1区域),右边的3区域会显示随着十斤啊的变化内存使用的折线图,同时在4区域会显示内存使用的详细信息,以及对象分配情况
- b. 点击Leaks模版(图中2区域)可以查看内存泄漏情况。如果在3区域中有红x出现,则有内存泄漏,4区域则会显示泄漏的对象
- 3)打开Leaks进行监测:
-
点击泄漏对象可以在(下图)看到它们的内存地址,占用字节,所属框架和响应方法等信息,打开扩展视图,可以看到右边的跟踪堆栈信息
-
4)监测结果的分析:
- 5)Allocations—内存分配版本的介绍
-
Allocations是监测程序运行过程中 内存分配情况的,也需要同时运行着程序。界面情况如下:
- 双击某一个方法,同样会跳转到代码中,会有每一句代码对应的内存分配情况,根据这些信息,可以对程序里不同代码的内存占用情况有一些认识,并进行针对性优化
- 1)CMD + i 打开
具体使用
- 1>. Allocations纪录了内存分配,用来优化内存使用的
- 2>. Leaks用来分析内存泄漏。ARC中引起的内存泄漏原因就是引用环
-
第一步:先选择Leaks和Leaks by Backtrace.这里可以看到那些对象内训泄漏了,泄漏了多少,这个就是简单看看,没有太多调试意义
-
第二步:然后看看Call Tree,因为Call Tree会给我们大概的位置,有时候会给我们精确的位置,不过要看运气了。
然后,再右面选择Invert Call Tree和Hide System Library
- 双击上图中的任意一行,就会跳到代码处内存泄漏的地方(事实上,到这步,很多内存泄漏的问题都会被发现),当然也有一些泄漏还是看不出来的
- 第三步
-
然后我们选择对ARC调试很有用的一部分Circles & Roots,通过这个我们可以看到详细的ARC引用计数过程。然后,我们看到如下图
- 小的红色矩形点击可以看出引用计数的详细信息(ARC就是自动引用计数,计数为0,则对象会被释放)
- 大的红色矩形可以描绘对象引用环的图,这里如果是我们自己的东西,就能看出来哥哥对象的引用
- 如果这里没有引用环的图,首先我们找一下我们自定义的对象,正常完成任务这个对像就应该释放了,为了确认这个对象有释放,可以重写dealloc方法,在此方法中log释放信号,看看是否被释放
- 如果这里就是没有释放,我们可以点击这里对象后的箭头详细查看下,这个对象的引用计数变化如图
- All 代表所有的引用计数变化
- Unpaired表示那些未成对的变化·· (成对就是Leaks识别出了对应的+1,-1)
- By Group会把相应的变化分成一组
-
ByTime会按照顺序列出引用计数变化
- 总结:其实大多数问题在双击上文的代码部分就可以解决了,少数问题需要详细的分析ARC引用过程,
-
建议如果我们未发现表示内存泄漏的红x,但是我们想进一步评估某个对象对于内存的应用,可以看看Allocations模版的折线图,反复执行从
创建对象 -> 销毁对象
这个过程,如果总占用内存数会随之增加,这说明这个对象没有释放,有些时候虽然占用的对象不是很严重,但是也会增加占用内存,因此必须释放这个对象 - 提示:有些情况下,对象没有释放是无法检测到的,反复监测内存占用也没有明显的增加,这是最好在配置比较低的设备上测试一下。
文章学习路径:关于Instruments-Leaks工具的归纳总结