拾遗补陋之 Instruments

Time Profiler

Time Profiler 是 Instruments 里用来来检测CPU耗时的工具。如果你想知道某个操作或行为对CPU的影响,都可以通过这个工具进行分析。Time Profiler 在运行时,会按照指定间隔(默认1毫秒)去会追踪每一个线程的实时堆栈信息,并通过比较间隔时间的堆栈状态,来推算出某个方法执行了多久。

默认,Time Profiler 的右下角属性面板里, 只有 Separate By Thread 这个过滤开关是默认打开的。这个开关仅仅将所有操作,按线程进行分隔,因此我们还不能直观地看到有效信息,这里面夹杂了许多系统函数和一些递归调用等等。

所以,我们需要重新设置过滤条件。暂时关闭左上角的运行开关,等待彻底停止并且开关变成亮红色圆球之后,选择多一些条件:

再次启动Time Profiler 之后,点击某一个线程。我们就能够更清晰地每个函数的耗时了。

除了Call Tree面板上的开关以外,在第一个标签下有一个 Record Waiting Threads 的开关也非常有用。

一般来说,当我们的程序因为访问mutex对象被锁定时,或者是因为等待一个网络packet到来而处于Idle状态时,这些情况下都不会消耗CPU时间。此时,如果没有勾选 Record Waiting Threads 开关,Time Profiler不会去记录等待过程中的消耗。但是,这种情况会造成一些操作活动的停滞,确确实实影响到了体验,我们在分析时需要综合去考虑这些情况。而假如我们勾选该按钮后,Time Profiler 会将这些等待时间囊括进来。

在我的示例里,勾选 Record Waiting Threads 后,运行Time Profiler 可以看到 sessionStep 有将近5秒的耗时:

双击sessionStep行查看代码,可以看到函数内部有一行休眠5秒钟的代码:

参数信息:

Setting State
Separate By Thread 默认Open,将活动按照线程进行分离,这样可以清晰地看到占用CPU最大的线程。
Invert Call Tree 反向显示调用树。比如 FunC{FunB{FunA}} 在显示时会显示 FunA->FunB->FunC的层级关系。
Hide System Libraries 隐藏系统库文件。过滤掉各种系统调用,只显示自己的代码调用。
Flattern Recursion 拼合递归。将同一递归函数产生的多条堆栈(因为递归函数会调用自己)合并为一条。
Top Functions 找到最耗时的函数或方法。
Record Waiting Threads 记录等待状态的耗时。

Allocations

1,Statistics(统计模式)

当开发者选择该模式时,Allocations 会显示指定时间内每一种类型的所有对象在App内存中的分配情况。默认会显示从App启动到当前时间点统计到的内存信息。

当然,我们也可以选择查看指定时间段的内存变化情况。比如,在我的示例中,我从网上下载了9张图片,这9张图片下载完成后会被解析并转化成相应的内存对象ImageIO_PNG_Data。点击追踪面板并选中一个起始时间,然后往后方拖拽并在你觉得合适的位置停下,该动作结束之后 Allocations 会统计出这段时间内,你的内存变化情况,如下图:

如果你已经对每一列数据所代表的有所了解信息,你就会发现在Persistent Bytes(净分配内存)这一列,ImageIO_PNG_Data变化为11Mb,也就是说在该时间段内存净增加了11Mb。(如果不太直观,可以点击表头对数据从大到小进行一下排序。)

Column name Definition
Graph 筛选在追踪面板上的显示对象
Category 通常为 Core Foundation 对象、Objective-C类或者是一个block内存块
Persistent Bytes 净分配内存,当前已分配但是仍然没有被释放的内存大小。
#Persistent 净分配数,当前已分配但是仍然没有被释放的对象或内存块的数量
#Transient 已分配并且已经被释放的对象或内存块的数量。
Total Bytes 总分配字节数,所有已经分配内存包括已经被释放了的内存大小。
#Total 总分配数,所有已经分配的对象或内存块数量,包括被释放的对象或内存 
块的总数,即(#Total = #Persistent + #Transient)
Transient/Total Bytes 这一列显示一个已释放的内存和总分配内存的比例图

2,Generations

在Generations模式下,开发者可以通过右侧的 Mark Generation按钮来生成某个时间点的内存快照,最好多次生成快照并比较快照之间的内存差异:

Generation I 和 Generation H之间的内存变化,就是上面用统计模式分析图片缓存的地方。

Column name Definition
Snapshot 快照的名字
Timestamp 生成快照的时间点
Growth 与上一个快照相比,净增加的内存
#Persistent 净分配数,当前已分配但是仍然没有被释放的对象或内存块的数量

3,Call Tree

这种模式和Timer Profiler的使用方式类似,都是通过设置过滤项来筛选,不做熬述。

示例

参见

Comments