Instruments 性能检测

先来一发苹果官网上Instruments User Guide,其实没啥用,英语不好的也懒得去看。(反正我是看不懂)

111440398-b523ad66638b643f

关于Instruments有网友如是说的:“一句话: 内存开销、运行速度、内存泄露 and so on”。

如此简单的回答肯定打发不了咱们各位看官和面试官,当然上述表达和下边的网友总结的意思是一样的:

问:您一般是怎么使用Instruments的?

这个问题也就是考察下你经验如何了, Instruments里面工具很多,也没必要逐一说明,挑几个常用的说下就好:

Time Profiler:分析代码的执行时间,找出导致程序变慢的原因。

Zombies:检查是否访问了僵尸对象,但是这个工具只能从上往下检查,不智能

Allocations:用来检查内存分配,写算法的那批人也用这个来检查

Leaks:检查内存,看是否有内存泄露

还有对Instruments这么理解的,说的也不错:Instruments的价值在于,它使我们深刻理解我们代码的内部运作

好了,那么就开始我们自己的Instruments之旅吧,揭开神秘面纱。

注:本文大部分篇幅将讲述Allocations、Leaks、Time Profiler、Zombies这四项,因为是经常用到的,其他的可能简单介绍或者一带而过。

关于Instruments的概述请参考Instruments概述,可以整体的理解一下Instruments。

首先我们要知道怎么打开这个Instruments:在xcode中有好几种打开的方式,具体如下:

1、

121440398-0207284b7ddeb131

2、

131440398-d49417c06b4ec94e

3、长按启动按钮,选择Profile

141440398-e8374b8185243d3e

Instruments页面如下,里面全是英文,笔者为大家用有道翻译了一下,哪里不对,希望大家告知,我进行修改。

151440398-e98e11e264232abe

其实我们可以看到xcode开发人员的用心,一些图片上边的标志我们一看就能明白是什么意思,例如能量诊断,其实就是手机上边的电池嘛🔋,还有泄漏,就是一个管子,有水滴💧滴下来了,就是泄漏的意思。还有网络,就是一个信号塔发射信号的意思。有的看不懂没关系,我这不是给大家翻译了嘛。

另外有的时候Instruments的启动按钮是启动不了的,这怎么办呢,有大神给提供了一种解决方案:Instruments启动按钮不可点。(在这里谢谢标哥大神,虽然你也不看我的博客哈哈)

大概的解决方案就是:各种重启。手机关机、重启,同时将Xcode关掉,然后重新打开Xcode,然后重新将手机与电脑连接,再打开Instrument,点击Core Animation,切换到当前的手机,发现可以正常点击了。

在这里有必要说一句,这19个性能检测的工具,有的可以在模拟器上边进行检测,有的是不可以的。如果选择使用ios模拟器,那么它监控的就会是你的mac,和真机还是有区别的,譬如这个电池就应该用真机检测,模拟器的电池没啥可测的。而我们的目的是手机app,当然,所有的项目都是都可以在真机上检测的。建议大家尽量在真机上用Istrunments。下边我们就逐一看看这19个性能检测是怎么操作的,到底怎么就检测了呢,检测出来的都是什么东西呢,会得到什么样的结果呢,我们拭目以待。

1、Blank

空白的,没啥可说的。

2、Activity Monitor 活动监视器

监测CPU、内存、硬盘和网络使用情况,还能检测所有的进程,检测父/子进程的层次。默认情况下显示:虚拟内存大小,cup总使用量,cup用户所使用的占用比,cpu系统使用占用比。推荐学习小白学习Activity Monitor

161440398-45d96b32f3ab6177

第1部分是profile的表头,启动、暂停、项目名称、运行时间等等信息都可以在上边找到。

第2部分是左边是性能检测的项目名称,右边以竖形条形式展示运行过程中数据值的大小,比较直观。

第3部分是具体的性能数值,可以选择Details(详细信息)和Console(控制台),可以看到具体的详细信息。

3、Allocations 分配:

(!!重点之一来了!!来得如此之快,还叫人有些不适应呢)

为什么我们要使用这个Allocations,参考Alloactions简单使用。文章中介绍了原因:

171440398-4e1370d4ae818970

Allocations 的页面如下所示:

181440398-d68d941aa032c25b

1:堆区内存和虚拟内存占用图

2:堆区内存占用图

3:虚拟内存跟踪图

4:选择使用不同的形式展示内存占用情况

5:勾选让上面曲线图展示对应内存占用情况

6:持久分配的内存所占字节数(未释放)即该类对象在内存中占得总内存

7:持久创建的对象个数(未释放)即该对象存在于内存中的个数

8:临时分配的对象个数(未释放)即存在过已经被回收的对象的个数

9:分配的所有内存所占字节数(未释放)

10:创建的对象总数(未释放)

11:设置面板,不同的设置使左边有不同展示效果

如上图并不能很好的了解每个方法所占用的内存情况,接下来我们点击4的call Trees如下图设置:

191440398-c42e4fb92085a826

接下来我们根据内存泄漏的情况对内存分配进行分析,内存泄漏分两种:

第一种:为对象A申请了内存空间,之后再也没用到A,也没有释放A导致内存泄漏。这种是Leaked Memory内存泄漏。

第二种:类似于递归,不断的申请内存导致的内存泄漏。根据下边的链接文章我们知道这种情况就是Abandoned Memory被遗弃的内存。

说到这里大家可以去看看这篇文章iOS Instruments,名字虽然起的很一般,但是讲了Allocations的前因后果。当然,下文我也拿来借鉴了。在此,谢谢文章作者luobs。

第二种情况根据以下图的操作可以清晰的找到对应的问题代码,当然不一定是我们自己代码的原因,也有可能是系统框架的问题。

201440398-d7b18f84b7056f06

211440398-5e47bfea247d855a

下边是关于寻找这个Abandoned Memory被遗弃的内存的方法:

221440398-520b2f9411c5d60f

231440398-654d8bb7d708a585

该方法笔者没有亲测,但是看着挺可靠的,具体的步骤告诉了,按照步骤一步一步的走下来应该就能找到被遗弃的内存(看到这个“被遗弃”的词,就想起了《纪念碑谷》)

4、Automation:自动化  

UI 自动测试是iOS 中重要的附加功能,它由名为“Automation”的新的工具对象支持。Automation工具的脚本是用JavaScript语言编写,主要用于分析应用的性能和用户行为,模仿/击发被请求的事件,利用它可以完成对被测应用的简单的UI测试及相关功能测试。

简单的说就是自己写JS脚本进行测试。(最好了解JS语言最好了,不了解的这个Automation其实有点鸡肋)

可以参考下边这篇文章借鉴他人UI Automation

241440398-d35280037b23748a

251440398-43529466b72887fa

261440398-29c30c91dbc5641e

5、Cocoa Layout:自动布局 

Cocoa Layout可以应用于iOS模拟器和Cocoa桌面应用,但是不能和连接的iOS设备一起使用。Cocoa Layout提供了一个与NSLayoutConstraint类的实例有关的所有事件的时间轴,这一点和回溯(backtrace)很像。

关于这项内容网上资料并不多,大家可以参考利用Cocoa Layout 检视自动布局

271440398-3c3a4ab5b8e35115

6、Core Animation:核心动画 

 在网上查资料,大部分都是关于动画怎么设置的,和layer有关的动画制作,即便前面加上Instruments,查出来的也是关于动画制作的。。。也是醉了。幸好我们同事之前总结过关于这方面的,直接拿来用吧。如果大家有相关的链接,希望能给提供一下,谢谢了。

这里我们需要知道这个Core Animation是干什么的,Core Animation工具是用来检测Core Animation性能的。(看起来这句话好像说了等于没说,不过从这句话里面我们可以看出加粗的Core Animation是我们网上查到的利用iOS做的动画,而前面没有加粗的是咱们Istruments里面的Core Animation工具)

首先我们了解什么是FPS。FPS:一秒钟渲染多少帧 Frame Per Second = FPS。

Core Animation给我们提供了周期性的FPS,并且考虑到了发生在程序之外的动画,界面滑动FPS可以进行测试。一般FPS是60左右,过于低的话需要进行优化。根据下图我们会发现,过于低的数值是低于45

 281440398-9f49d5bbafc95a97

291440398-d98cf216f7e82ea1

301440398-644c60029d66adb3

看上图,我们主要介绍右边“设置”里面的相关内容。

Color Blended Layers混合过度绘制

这个选项基于渲染程度对屏幕中的混合区域进行绿到红的高亮(也就是多个半透明图层的叠加)。由于重绘的原因,混合对GPU性能会有影响,同时也是滑动或者动画帧率下降的罪魁祸首之一。

这样就能在模拟器上边看到这个Color Blended Layers

311440398-3aa4c667ab8d6614

GPU每一帧可以绘制的像素有一个最大限制(就是所谓的fill rate),这个情况下可以轻易地绘制整个屏幕的所有像素。但是如果由于重叠图层的关系需要不停地重绘同一区域的话,掉帧就可能发生了。

GPU会放弃绘制那些完全被其他图层遮挡的像素,但是要计算出一个图层是否被遮挡也是相当复杂并且会消耗处理器资源。同样,合并不同图层的透明重叠像素(即混合)消耗的资源也是相当客观的。所以为了加速处理进程,不到必须时刻不要使用透明图层。任何情况下,你应该这样做:

给视图的backgroundColor属性设置一个固定的,不透明的颜色

设置opaque属性为YES

注意下边的内容为我们解释了为什么在tableview性能优化中我们提到的平衡CPU和GPU里面关于Core Animation的原因。

(关于CPU和GPU可以参考CPU与GPU

如果用到了图像,尽量避免透明除非非常必要。如果图像要显示在一个固定的背景颜色或是固定的背景图之前,你没必要相对前景移动,你只需要预填充背景图片就可以避免运行时混色了。

如果是文本的话,一个白色背景的UILabel(或者其他颜色)会比透明背景要更高效。

Color Offscreen-Rendered Yellow(离屏渲染)

 

这里会把那些需要离屏渲染的图层高亮成黄色。这些图层很可能需要用shadowPath或者shouldRasterize来优化。

当图层属性的混合体被指定为在未预合成之前不能直接在屏幕中绘制时,屏幕外渲染就被唤起了。屏幕外渲染并不意味着软件绘制,但是它意味着图层必须在被显示之前在一个屏幕外上下文中被渲染(不论CPU还是GPU)。图层的以下属性将会触发屏幕外绘制:

1、圆角(当和maskToBounds一起使用时)

2、图层蒙板

3、阴影

屏幕外渲染和我们启用光栅化时相似,除了它并没有像光栅化图层那么消耗大,子图层并没有被影响到,而且结果也没有被缓存,所以不会有长期的内存占用。但是,如果太多图层在屏幕外渲染依然会影响到性能。

有时候我们可以把那些需要屏幕外绘制的图层开启光栅化以作为一个优化方式,前提是这些图层并不会被频繁地重绘。

对于那些需要动画而且要在屏幕外渲染的图层来说,你可以用CAShapeLayer,contentsCenter或者shadowPath来获得同样的表现而且较少地影响到性能。

Color Hits Greenand Misses Red(光栅化缓存图层命中情况)

当使用shouldRasterizep属性的时候,耗时的图层绘制会被缓存,然后当做一个简单的扁平图片呈现。当缓存再生的时候这个选项就用红色对栅格化图层进行了高亮。如果缓存频繁再生的话,就意味着栅格化可能会有负面的性能影响了。

Color Copied Images 拷贝的图片

有时候寄宿图片的生成意味着Core Animation被强制生成一些图片,然后发送到渲染服务器,而不是简单的指向原始指针。这个选项把这些图片渲染成蓝色。复制图片对内存和CPU使用来说都是一项非常昂贵的操作,所以应该尽可能的避免。

Color Immediately  颜色立即更新

通常Core Animation Instruments以每毫秒10次的频率更新图层调试颜色。对某些效果来说,这显然太慢了。这个选项就可以用来设置每帧都更新(可能会影响到渲染性能,而且会导致帧率测量不准,所以不要一直都设置它)。

Color Misaligned  Images(图片的不正常缩放)

-这里会高亮那些被缩放或者拉伸以及没有正确对齐到像素边界的图片(也就是非整型坐标)。这些中的大多数通常都会导致图片的不正常缩放,如果把一张大图当缩略图显示,或者不正确地模糊图像,那么这个选项将会帮你识别出问题所在。

Color OpenGL Fast Path Blue

 

这个选项会对任何直接使用OpenGL绘制的图层进行高亮。如果仅仅使用UIKit或者Core Animation的API,那么不会有任何效果。如果使用GLKView或者CAEAGLLayer,那如果不显示蓝色块的话就意味着你正在强制CPU渲染额外的纹理,而不是绘制到屏幕。

Flash Updated Regions(Core Graphics绘制的图层)

-这个选项会对重绘的内容高亮成黄色(也就是任何在软件层面使用Core Graphics绘制的图层)。这种绘图的速度很慢。如果频繁发生这种情况的话,这意味着有一个隐藏的bug或者说通过增加缓存或者使用替代方案会有提升性能的空间。

7、Core Data  核心数据 

 依旧是我们在网上查找资料,好多资料都是关于如何使用CoreData存储数据的,即便我们在前面加上Istruments,查到的资料还是关于如何存储数据的,还好我们另一位同事找到了资料。

Core data也叫检测核心数据故障的仪器,主要是用于监测读取、缓存未命中、保存等操作,能直观显示是否保存次数远超实际需要。以下的instruments工具收集的数据和Core Data应用的事件相关。你可以使用这些instruments工具返回的信息来评估各种事件对应用性能的影响和来定位潜在问题并修复它。

Core data instrument工具可以运行在单一进程或所有系统当前运行的进程之上。它只会记录使用Core Data的进程的数据。该instrument工具在实现上使用了DTrace,并可以导入DTrace脚本。

321440398-98c57866c9caf224

Core Data Fetches 工具记录Core Data应用中提取保存数据的操作。

Core Data Cache Misses 工具记录高速缓存未命中导致的故障事件。

Core Data Saves 工具记录了Core Data应用中保存的操作。

8、Counters  计数器    

从用户管理的点事件计数器仪器记录信息。它可以记录从一个过程或系统上运行的所有进程的信息。

9、Energy Diagnostic  能量诊断   

用于Xcode下的Instruments来分析手机电量消耗的。(必须是真机才有电量)

10、File Activity  文件活动  

按照介绍this template monitors file and directory activity ,including file open close calls,file permission modifications, directory creation ,file moves ,etc.翻译过来是:这个模板活动监视器文件和目录,包括文件打开或者关闭,文件权限修改,目录创建,文件移动等。

11、GPU Driver 显卡驱动程序 

GPU Driver可以测量GPU的利用率,同样也是一个很好的来判断和GPU相关动画性能的指示器。它同样也提供了类似Core Animtaion那样显示FPS的工具

331440398-8569fee98e0ce460

341440398-69ec5a5cb4d0d285

看来这个GPU Driver 还是和Core Animation有关。

12、Leaks 泄漏  

(!!又一个重头戏来了!!)

首先我们看一看内存溢出和内存泄漏的区别。

内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。

内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。

memory leak会最终会导致out of memory!

在前面的ALLcations里面我们提到过内存泄漏就是应该释放而没有释放的内存。而内存泄漏分为两种:Leaked MemoryAbandoned Memory。前面我们讲到了如何找到Abandoned Memory被遗忘的内存,现在我们研究的就是Leaked Memory。

351440398-0bd1c8d1995ffa51

发生的方式来分类,内存泄漏可以分为4类:

常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。

偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。

一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。

隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。

影响:从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。

下边我们介绍Instruments里面的Leaked的用法,首先打开Leaked,跑起工程来,点击要测试的页面,如果有内存泄漏,会出现下图中的红色的❌。然后按照后边的步骤进行修复即可。

361440398-482e80e6ff4390db

371440398-f0760e0a503c8c40

381440398-2a353cef7eb3812d

下图是对Leaked页面进一步的理解:

391440398-cfe69945d6a4e955

当然了,关于内存泄漏我们还可以用 command +shift +B 的方式进行检测,这个快捷键调起的是内存管理器Analyze。

也可以从Product里面直接打开

401440398-3337621889b43bcc

关于内存管理器Analyze解决问题可以参考这篇文章APP Analyze(静态分析)也可以参考Analyze问题解决

使用内存管理器遇到的问题大概分为:

1、garbage value(垃圾值)

2、never read(分配了空闲内存)

3、Null passed to a callee that requires a non-null 1st parameter(Null赋值给非空对象)

4、Potential leak of an object stored into ‘XX'(存在潜在的内存泄露)

上述两篇文章很好的解答了出线这4个问题如何解决,这里就不赘述了。

关于内存泄露还是比较重要的,大家看看,测试一下自己项目里面的内存泄漏,另外如果大家有什么更好的方法,希望能够告诉我,谢谢。

使用上述两种方法(1)Instruments-Leaked (2)内存管理器Analyze  来检查内存泄漏,是我们最常用的两种。

13、Metal System Trace  

金属系统跟踪  

翻译下图红框的英文得到:金属ios系统跟踪配置文件的性能应用程序从应用程序通过提供跟踪信息,司机和GPU层。(狗屁不通)从网上找Metal System Trace相关的资料也没有找到。谁知道这是干啥用的。

411440398-5216651620a01def

14、Network 网络

同样是翻译下边的英文:分析应用程序如何使用TCP / IP和UDP / IP连接使用连接仪器。就是检查手机网速的。(这个最好是真机)

15、OpenGL ES Analysis  openGL分析  

同样是翻译下边的英文:这个模板的措施和分析OpenGL ES活动检测OpenGL ES正确性和性能问题也提供了解决这些问题的建议。

16、System Trace  系统跟踪  

该模板提供了系统行为的全面信息。它显示线程何时调度,并显示从用户到系统代码的线程转换,通过系统调用和内存操作。这个模板可以在OS X操作系统和iOS上使用。包含三个模板

Scheduling  Instrument——调度工具

System Calls  Instrument—系统调用仪器

VM Tracker   Instrument—–VM跟踪仪

17、System Usage  系统使用 

这个模板监视一个应用程序和记录系统的I / O活动相关的文件,套接字和共享内存。这包括输入,输出,时间回溯,调用树,乃至每一次响应。该模板只可用于iOS包含一个模板

I/O Activity    Instrument—–I/O活动仪

I/O Activity instrument工具记录I/O事件:函数调用,比如在文件系统上面的read、write、open、close等操作。你可以使用该instrument工具来启动和样本分析单个运行在iOS设备上面的进程。尽管I/O Activity instrument工具提供了一个调用树的回溯跟踪视图,在Mac  OS X上有类似I/O Activity instrument工具的fs_usage实用工具。

18、Time Profiler  时间分析器 

(又一个重头戏!!!)

用来检测app中每个方法所用的时间,并且可以排序,并查找出哪些函数占用了大量时间。页面如下:

421440398-419a4530df61be5a

使用Time Profile前有两点需要注意的地方:

1、一定要使用真机调试

在开始进行应用程序性能分析的时候,一定要使用真机。因为模拟器运行在Mac上,然而Mac上的CPU往往比iOS设备要快。相反,Mac上的GPU和iOS设备的完全不一样,模拟器不得已要在软件层面(CPU)模拟设备的GPU,这意味着GPU相关的操作在模拟器上运行的更慢,尤其是使用CAEAGLLayer来写一些OpenGL的代码时候,这就导致模拟器性能数据和用户真机使用性能数据相去甚远

2、应用程序一定要使用发布配置

在发布环境打包的时候,编译器会引入一系列提高性能的优化,例如去掉调试符号或者移除并重新组织代码。另iOS引入一种”Watch Dog”[看门狗]机制,不同的场景下,“看门狗”会监测应用的性能,如果超出了该场景所规定的运行时间,“看门狗”就会强制终结这个应用的进程。开发者可以crashlog看到对应的日志,但Xcode在调试配置下会禁用”Watch Dog”

431440398-51fd6c89d63d6e6e

下面解释了每一个选项对左侧列表中数据的显示起了什么作用:

Separate by Thread:每个线程被单独考虑。这能让你知道哪一个线程占用CPU最多。

Invert Call Tree:选中该选项后,调用栈会自上至下显示。这通常是你需要的,因为你想知道CPU花费时间的那个最深的方法。

Hide System Libraries:选中该选项后,只有你自己app中出现的符号会被显示出来。通常选中该选项是有用的,因为你只关心CPU在你自己的代码中的哪一部分花费时间,你没法对系统库使用CPU做多少改变。

Flatten Recursion:该选项将每一个调用栈中的递归函数(调用它们自身的函数)视作单一入口,而不是多入口。

Top Functions:选上这一选项让Instruments将花费在一个函数中的总时间视作在该函数中直接花费的时间加上调用的其他函数花费的时间。所以如果函数A调用了函数B,那么函数A花费的总时间被记为A花费的时间加上B花费的时间。这一选项非常有用,因为它能让你在每次进入调用栈时找到花费最长的时间,瞄准你最耗时的方法。

看到网上有人说主线程耗时过多进行优化的,有的是网络请求耗时过多进行优化的,有的是UIImage耗时过多进行优化的,总之,可以看到哪个函数耗时多,进而优化,在这里不由得想起了本文开头提到的一位网友说的:Instruments的价值在于,它使我们深刻理解我们代码的内部运作。诚不欺吾。

总结:性能优化是在所有更能实现完成时要做的事,使用Time Profile工具分析app每个流程的执行情况,发现耗时的地方,合理优化,提升用户体验,切记,优化后要做一遍详细的测试,别修了东墙坏了西墙。

19、Zombies  僵尸  

(最后一个,也是最后一个重头戏)

翻译英文:专注于检测过度释放的“僵尸”对象。还提供了数据对象分配的类以及所有活动分配内存地址的历史。

这里我们可以看到一个词语叫“over-release”,过度释放。我们在项目中见到最多的就是“EXC_BAD_ACCESS”或者是这样的:Thread 1: Program received signal:”EXC_BAD_ACCESS“,这就是访问了被释放的内存地址造成的。过度释放,是对同一个对象释放了过多的次数,其实当引用计数降到0时,对象占用的内存已经被释放掉,此时指向原对象的指针就成了“悬垂指针”,如若再对其进行任何方法的调用,(原则上)都会直接crash(然而由于某些特殊的情况,不会马上crash)。过度释放简单的说就是对release的对象再release,就是过度释放。

我们需要知道这几个概念:

1、内存泄漏:对象使用完没有释放,导致内存浪费。

2、僵尸对象:已经被销毁的对象(不能再使用的对象)

3、野指针:指向僵尸对象(不可用内存)的指针。给野指针发消息会报EXC_BAD_ACCECC错误。

4、空指针:没有指向储存空间的指针(里面存的是nil,也就是0)。在oc中使用空指针调中方法不会报错。

注意:为了避免野指针错误的常见方法:在对象被销毁之后,将指向对象的指针变为空指针。

对于过度释放的问题,可以直接使用Zombie,当过度释放发生时会立即停在发生问题的位置,同时结合内存分配释放历史和调用栈,可以发现问题。至于上文提到的不会crash的原因,其实有很多,比如:

对象内存释放时,所用内存并没有完全被擦除,仍有旧对象部分数据可用

原内存位置被写入同类或同样结构的数据

我们将僵尸对象“复活”的目的:僵尸对象就是让已经释放了的对象重新复活,便于调试;是为了让已经释放了的对象在被再次访问时能够输出一些错误信息。其实这里的“复活”并不是真的复活,而是强行不死:这么说吧 相当于 他的RC=0的时候 系统再强行让他RC=1,顺便打上一个标记 zoom,等到你去掉那个沟以后 系统会把带有标记zoom的对象RC=0。

可以参考IOS性能调优系列:使用Zombies动态分析内存中的僵尸对象

可以参考iOS 遇到EXC_BAD_ACCESS解决方法

可以参考ios 调试技巧收藏 一 解决EXC_BAD_ACCESS错误的一种方法–NSZombieEnabled

可以参考野指针与僵尸对象

下边是Instruments里面的Zombies的用法:

441440398-b7c3198642a0f036

接下来进行设置,在Launch  Configuration中勾选Record reference counts和Enable NSZombie detection。其中Recordreference counts是显示引用计数,Enable NSZombie detection是能够检测僵尸对象。

451440398-e5b737becf5a687c

这样在程序运行的时候,如果发现僵尸对象它就会弹出一个对话框,点击其中“→”按钮,在屏幕的下方会显示僵尸对象的详细信息,下图可以看到僵尸对象的引用计数变化情况。

461440398-3ee586361ed60de0

注意:Zombies模版在使用的时候会导致内存的飙升,这是因为所有被释放的对象被僵尸对象取代,并未真的释放掉,在结束Zombies时会释放,这是预知行为,这就意味着instrument里的其它工具和Zombies是不能同时使用的,Zombies会导致其它的数据不准。包括leaks,你也不应该把它加到Zombies模版中,即使这么做了结果也没什么意义。对于iOS应用来说,在用Zombies模版时使用iOS模拟器比真机要好。

另外XCode也提供了手动设置NSZombieEnabled环境变量的方法,不过设置NSZombieEnabled为True后,会导致内存占用的增长,同时会影响Leaks工具的调试,这是因为设置NSZombieEnabled会用僵尸对象来代替已释放对象。

点击Product菜单Edit Scheme打开该页面,然后勾选Enable Zombie Objects复选框:

471440398-d1201645e5c89487

最后提醒的是NSZombieEnabled只能在调试的时候使用,千万不要忘记在产品发布的时候去掉,因为NSZombieEnabled不会真正去释放dealloc对象的内存,一直开启的话,该死去的对象会一直存在,后果可想而知,自重!

好了,结束了。还是那句话:Instruments的价值在于,它使我们深刻理解我们代码的内部运作

最后,哪里不对的地方可以给我留言,我会及时改进的,谢谢大家。

1 3 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部