(译)Profile Your App’s Memory Usage

2024-04-24 14:52:03 浏览数 (2)

1.关于内存分析

不论何时,只要app创造对象,内存就会为它分配一块空间,通常情况下,app需要跟踪这些创建的对象,并在不需要的时候释放它们,好让内存可以为其他的对象分配空间。而ARC可以让系统自动管理这些内存,可以使工作变得更简单,通过ARC,系统能够监控对象的创建,并在合适的时候释放,从而留给app很少的事情去做。但不论多少内存被管理,即使是最好的app设计也会偶尔碰到一些很难以解决的内存问题。

instruments能够图表化app的内存使用情况,使得它更容易的找到潜在问题的范围,它甚至能自动的甄别出某些内存问题的类型,并标记它们给开发者分析,使用instrument主要用来监控和跟踪以下内容:

1.内存总体使用情况:工具能够在一个较高的层次上去展现你的app的内存使用情况,并于其他的活动进程的内存使用情况进行比较,从而可以找到那些增幅较大的,或者不希望增长的内存。

2.内存泄漏:就是那些在某些时候创建了的内存空间,但一直没有被释放,并且也不再被应用程序使用,因为没有引用它的指针,所以即无法被释放也无法被再次使用,例如,假设你写了一个app,在一个画布上创建了一个长方形对象,但在画布关闭之后没有释放这个对象,在这种情况下,程序中只要有包含长方形对象的画布被关闭,就会出现泄漏,而且泄漏会越来越多。要想修复这个泄漏,就需要发现是哪个对象没有被合理的释放,然后修改app程序,在适当的时候释放它,

3.被遗忘的内存:就是那些由于一些原因,app 分配了一些内存空间,但是它其实是没有被用到,或者将不会被引用,比如,你的app去缓存一个已经保存过的图片,从而造成了用两倍的空间去储存图片,或者,你的app一直在维护一个多对象的数组为了在以后能够访问它,但其实从来没有访问过,不想内存泄漏,被遗忘的内存会依然被你的app所引用,只是没有提供用处。因为从技术角度讲它们是有效的,所以对于imstrument来说发现它们是十分困难的一件事,需要开发者更多的检查工作去做

4.Zombies,一些内存已经释放,并不在被使用,但代码中仍有指向它的指针, 比如,假设你的app中包含了一个图像缓存,一旦缓存被请,你的app酒不应该尝试去引用这个之前的图像,如果去寻址这个不存在的图像就会被认为称为Zombies,即僵尸引用。

因为内存问题很难被发现,所以在app的不同阶段进行定期快照是一个非常好的方式,以此可以寻找那些意外的、无限制的内存增长,你能够通过比较快照去查明这些对象时如何被分配内存空间,如何被销毁,和这段时间内存是如何被使用的。

另外一种好的方法是,已经不断进行一些可重复的操作,即,让你的app进入一个新的状态,然后返回到初始状态,这种方法叫做generational analysis,每次你的app进入一个新的状态,一个迭代的对象被创造,在大部分情况下,当app返回到原始状态下,这些对象应该应该被释放,例如,如果你的app打开了一个窗口,当关闭窗口的时候,窗口里的任何对象都应该被释放,如果不是所有的都被释放,这就会带来一个内存问题,当进行generational analysis分析的时候,初始的迭代将会展示出比期望值更大的内存使用量,因此,为了能够更真实的冠绝,需要重复操作多次。

2.监控内存使用情况

暂时没有翻译

3.发现Abandoned Memory

这个Allocations分析模版使用了Allocations和VM Tracker两个工具去测量一般的内存使用情况和虚拟内存使用情况,然而,去跟踪那些已经被分配空间但没有被使用的Abandoned Memory,你需要严格的专注Allocations工具,这个工具会测量出堆内存的使用量和分配的轨道,包括哪些类分配的特殊对象

因为Abandoned Memory在app中仍然被引用,所以,工具不能分辨出它们是否重要,如果想要找到Abandoned Memory,你必须使用迭代分析去确认,当在反复操作某一个操作序列时,那块内存没有持续的增长,比如,开始和结束一个新的游戏,打开和关闭一个窗口,创操和删除一个对话,设置或者不设置某一个参数等等这些理论上app应该回到一个先前的稳定的内存状态。广泛的多次的循环操作应该不会导致那些不被期望的或者无限制的内存增长,instrument帮助我们把一段时间的内存增长关联到特定的对象分配上,从而你能够释放它们,降低你的app的内存占用

为了能够在app中返现abandoned memory 

1.打开instrument

2.当选择模版界面出现时,选择Allocations模版

3.从可选的设备和进程列表中选择你的设备和app

4.点击选择一个跟踪文档

5.点击时间轴窗口中Allocations

6.点击command+2按钮进入到设置界面 

7.点击    开始录制

8.在对应app上进行一次可重复的序列操作,为了能够更加准确,这一组操作的开始状态和结束状态应该是相同的

9.点击Mark Generation按钮,在跟踪轴上会出现一个标记,一系列的迭代结果将会展示在列表中,每一个迭代结果将会包含在这之前已经被分配空间的列表,当然,也可以在结束录制之后,在时间轴上拖倒三角符号到你想要的位置,然后点击Mark Generation按钮

10.重复8,9步骤,直到确认这段内存的增长是否是无限的 

11.点击按钮或者command-r结束录制

  1. 检查工具列出的列表 ,找到那些典型的重复内存增长,Growth 和# Persistent  两个指标将会告诉你这段时间内存增加了多少,和这段时间内存分配了多少,如果你的程序回到了起始状态后,理论上内存占用量不应该出现增长

 13.点击按钮将会显示出在这之前已经分配内存空间的新对象

14.寻找那些持续对象,如果发现存在,点击会出现它的实例

15.选择一个实例

16.按command+3会显示该实例的栈的跟踪序列的详细情况,该跟踪序列会提供一个完整的方法负责调用实例的列表。

17.点击Collapse button ( ),会隐藏系统调用的列表,这会让你更加更加容易定位你的方法

18.双击栈中的方法,将会显示在instrument中的代码行

19。点击右上方的Xcode按钮,可以编辑代码

20.判断这个内存空间是否有用,如果没有用,它就是Abandoned Memory,然后结局它!!!

4.发现内存泄漏

这个leaks模版使用Allocations 和 Leaks 工具去测量app的整体内存使用情况以及那些泄漏点——那些不再被引用且不可达的但被分配的内存空间的对象

寻找内存泄漏点:

1.打开工具

2.选leak择模版

3.选择对应的设备和程序

4.建立一个trace文档

5.点击录制按钮(就是那个红色的圆的按钮)

6.开始玩你的app

7.查看leak时间轴,如果有内存泄漏,在时间轴上会出现红色的长条

8.点击leak时间轴,下方会出现相关的信息

9.选择call tree 视图,这里将会展示被检测到的泄漏点的方法调用列表

10.按command+2出现界面设置界面

11.在call tree界面设置视图,选择Invert Call Tree 和 Hide System Libraries.

 这样可以倒序调用方法,从而使得最近调用的放在最上面,同时缩小方法调用的范围,如果是被app调用的话将会被标示黑色,并在前面加上

12.在call tree视图中选择一个你想研究的方法

13.按command +3会显示一个调用方法的栈序列

14.双击栈中的方法,将会显示它的代码

15点右上角xcode按钮可以进行编辑

通过使用backtrace来研究一个泄漏的对象

1.点击leak时间轴

2.选择泄漏的长条

3.选择一个你想研究的泄漏对象 

4.点击address列右边的箭头 将会显示出相应的引用计数和方法调用

5.按command+3显示对象的引用栈

6.点击Collapse button ( )会隐藏系统调用

7.双击栈里面的方法,将会显示其代码

8.点右上角的xcode将会进行编辑

通过cycles and roots来分析泄漏对象

1.点击leak时间轴

2.选择cycles and roots视图,将会循环展示出泄漏的对象

3.选择一个你想要的研究的对象

4.如果可以,看一下对象图

5.点击( )将会展示出这对对象的内存变迁的具体轴图(沿着引用计数器和方法调用的顺序)

6.按command +3会显示一个调用方法的栈序列

7.点击Collapse button ( )会隐藏系统调用

8.双击栈中的方法,将会显示它的代码

9点右上角xcode按钮可以进行编辑

通过call tree分析一个泄漏点

1.点击leak时间轴

2.选择call tree视图

3.按command+2出现界面设置界面

4.在call tree界面设置视图,选择Invert Call Tree 和 Hide System Libraries.

 这样可以倒序调用方法,从而使得最近调用的放在最上面,同时缩小方法调用的范围,如果是被app调用的话将会被标示黑色,并在前面加上

5.选择一个你想调查的方法

6.按command +3会显示一个调用方法的栈序列

7.点击Collapse button ( )会隐藏系统调用

8.双击栈中的方法,将会显示它的代码

9点右上角xcode按钮可以进行编辑

尽管instrument可以帮助你查找内存泄漏点,但你仍然需要仔细看相关的内存历史纪录和代码,从而可以定位和解决问题,下面的情形是比较典型能够引起内存泄漏的例子

1.retain之前没有进行release

2.一个对象被分配内存并初始化,但没有autorelease

3.如果泄漏点不是一个对象,那也许是因为调用的是api,但没有调用free();

0 人点赞