时间分析器
你要看的第一个工具是 Time Profiler
。在测量的时间间隔内,Instruments 将停止程序的执行并在每个运行的线程上执行堆栈跟踪。把它想象成按下 Xcode 调试器中的暂停按钮。这是 Time Profiler 的预览: -
此屏幕显示 Call Tree
。Call Tree
显示了在应用程序中以各种方法执行所花费的时间。每行都是程序执行路径所遵循的不同方法。在每种方法中花费的时间可以根据每种方法中分析器停止的次数来确定。例如,如果以 1 毫秒的间隔完成 100 个样本,并且发现特定方法位于 10 个样本中的堆栈顶部,那么你可以推断出总执行时间的大约 10% - 10 毫秒 - 花费了在那种方法中。这是一个相当粗略的近似,但它的工作原理! **** **** ****
从 Xcode’s
菜单栏中选择 Product\Profile
或 press ⌘I
。这将构建应用程序并启动仪器。你将看到一个如下所示的选择窗口:
这些都是仪器附带的不同模板。
选择 Time Profiler
仪器,然后单击选择。这将打开一个新的 Instruments 文档。单击左上角的红色记录按钮开始录制并启动应用程序。可能会要求你输入密码以授权仪器分析其他过程 - 不要担心,这里提供是安全的! 在“ 仪器”窗口中,你可以看到计时的时间,以及在屏幕中心的图形上方从左向右移动的小箭头。这表明该应用正在运行。
现在,开始使用该应用程序。搜索一些图像,并深入查看一个或多个搜索结果。你可能已经注意到,进入搜索结果的速度非常慢,滚动浏览搜索结果列表也非常烦人 - 这是一个非常笨重的应用程序!
嗯,你很幸运,因为你即将开始修复它! 但是,你首先要快速了解你在 Instruments 中所看到的内容。首先,确保工具栏右侧的视图选择器同时选择了两个选项,如下所示:
这将确保所有面板都是开放的。现在研究下面的截图以及它下面每个部分的解释:
1. 这些是记录控制。红色记录按钮将在单击时停止并启动当前正在分析的应用程序(它在记录和停止图标之间切换)。暂停按钮完全符合你的预期,并暂停当前应用程序的执行。
2. 这是运行定时器。计时器计算正在运行的应用程序运行的时间长度以及运行的次数。如果你停止然后使用录制控件重新启动应用程序,那将启动一个新的运行,然后显示将显示 2 的第 2 跑。
3. 这就是所谓的轨道。对于你选择的 Time Profiler 模板,只有一个仪器,因此只有一个轨道。你将在本教程后面的内容中详细了解该图的具体细节。
4. 这是细节面板。它显示了你正在使用的特定仪器的主要信息。在这种情况下,它显示的是最热门的方法 - 也就是那些耗尽了大部分 CPU 时间的方法。如果单击顶部显示调用树(左侧)的栏并选择样本列表,则会显示不同的数据视图。此视图显示每个样本。单击几个样本,你将看到捕获的堆栈跟踪显示在扩展详细信息检查器中。
5. 这是检查人员面板。有三个检查员:记录设置,显示设置和扩展详细信息。你很快就会了解其中一些选项。
钻深
执行图像搜索,并深入查看结果。我个人喜欢搜索狗,但选择你想要的任何东西 - 你可能是那些猫人之一!
现在,在列表中向上和向下滚动几次,以便在 Time Profiler
中获得大量数据。你应该注意到屏幕中间的数字在变化,图形填满了; 这告诉你正在使用 CPU 周期。
你真的不希望任何 UI 如此笨重,因为没有 table view
准备发货,直到它像黄油一样滚动! 为了帮助查明问题,你需要设置一些选项。
在右侧,选择“ 显示设置”检查器 (or press ⌘+2)
。在检查器中,在 Call Tree
部分下,选择“按线程分隔” ,反转,隐藏丢失的符号和隐藏系统库。它看起来像这样:
以下是每个选项对左侧表格中显示的数据的作用:
按线程分开: 每个线程应单独考虑。这使你可以了解哪些线程负责最大量的 CPU 使用。
反转调用树: 使用此选项,stack trace
从上到下进行考虑。这通常是你想要的,因为你希望看到 CPU 花费时间的最深层方法。
隐藏丢失的符号: 如果找不到你的应用或 system framework
的 dSYM
文件,那么你只需看到与二进制内部地址对应的十六进制值,而不是查看表中的方法名称(符号)。如果选择此选项,则仅显示完全解析的符号,并隐藏未解析的十六进制值。这有助于整理所呈现的数据。
隐藏系统库: 选择此选项后,仅显示你自己的应用程序中的符号。选择此选项通常很有用,因为通常你只关心 CPU 在你自己的代码中花费时间的位置 - 你无法对 system libraries
使用的 CPU 数量做多少工作 !
Flatten Recursion: 此选项将递归函数(自称为自称函数)视为每个 stack trace
中的一个条目,而不是多个。
顶部函数: 启用此选项使得 Instruments
将函数中花费的总时间视为该函数中直接时间的总和,以及该函数调用的函数所花费的时间。
因此,如果函数 A 调用 B,则 A 的时间被报告为在 A PLUS 中花费的时间在 B 中花费的时间。这可能非常有用,因为它允许你在每次下降到调用堆栈时选择最大的时间数字,归零在你最耗时的方法。
如果你正在运行 Objective-C
应用程序,还可以选择仅显示 Obj-C :如果选择此选项,则仅显示 Objective-C
方法,而不是任何 C
或 C++
函数。你的程序中没有,但如果你正在看一个 OpenGL
应用程序,它可能有一些 C++
,例如。
虽然某些值可能略有不同,但一旦启用了上述选项,条目的顺序应与下表类似:
嗯,这当然看起来不太好。绝大部分时间都用在将色调滤镜应用于缩略图照片的方法中。这不应该对你造成太大的冲击,因为表格加载和滚动是 UI 中最笨重的部分,而且当表格单元格不断更新时。
要了解有关该方法中发生的更多信息,请双击表中的行。这样做会显示以下视图:
那很有意思,不是吗! applyTonalFilter()
是一个在扩展中添加到 UIImage
的方法,在应用图像过滤器后花费了几乎 100 %的时间用于创建 CGImage 输出。
没有太多可以做的事情来加快速度:创建图像是一个非常密集的过程,并且需要花费很长时间。让我们试着退后一步,看看 applyTonalFilter()
的来源。单击代码视图顶部的痕迹路径中的 Call Tree
返回上一个屏幕:
现在单击表顶部 applyTonalFilter 行左侧的小箭头。这将展开调用树以显示 applyTonalFilter 的调用者。你可能还需要展开下一行; 在分析 Swift 时,调用树中有时会出现重复的行,前缀为 @objc。你对以应用程序的目标名称(InstrumentsTutorial)为前缀的第一行感兴趣:
在这种情况下,此行引用结果集合视图的 cellForItemAtIndexPath
。双击该行以查看项目中的关联代码。
现在你可以看到问题所在。应用音调滤波器的方法需要很长时间才能执行,并且它直接从 cellForItemAtIndexPath 调用,每当它要求过滤图像时,它将阻止 main thread
(以及整个 UI)。
分配
有关所有正在创建的对象和支持它们的内存的详细信息 ; 它还向你显示每个对象的 retain counts
。要重新开始使用新的 instruments profile
,请退出 Instruments 应用程序。这一次,构建并运行应用程序,并在 Navigators 区域中打开 Debug Navigator。然后单击 Memory 在主窗口中显示内存使用情况的图表:
这些图表可帮助你快速了解应用的效果。但是你需要更多的力量。单击 Profile in Instruments
按钮然后转移以将此会话带入仪器。该分配仪器会自动启动。
这次你会注意到两个曲目。一种称为分配,一种称为泄漏。分配轨道将在后面详细讨论; Leaks 轨道在 Objective-C 中通常更有用,本教程不会介绍。那你接下来要追查什么错误?项目中隐藏着一些你可能不知道的东西。你可能听说过内存泄漏。但你可能不知道的是,实际上有两种泄漏:
真正的内存泄漏是一个对象不再被任何东西引用但仍被分配的东西 - 这意味着永远不能重用内存。即使使用 Swift 和 ARC
来帮助管理内存,最常见的内存泄漏类型仍然存在。这是当两个对象彼此持有强引用时,每个对象使另一个对象不被释放。这意味着他们的记忆永远不会释放!
无限的内存增长是继续分配内存并且永远不会被释放的机会。如果这种情况持续下去,那么在某些时候,system’s memory
将被填满,你手上会有很大的记忆问题。在 iOS 中,这意味着应用程序将被系统杀死。
在应用程序上运行 Allocations 工具后,在应用程序中进行五次不同的搜索,但不会深入查看结果。确保搜索有一些结果! 现在让应用程序等待几秒钟。
你应该已经注意到 Allocations 轨道中的图形一直在上升。这告诉你正在分配内存。这个功能将引导你找到 unbounded memory growth
。
你要表演的是一个人。为此,请按名为 Mark Generation 的按钮。你将在显示设置检查器的顶部找到该按钮:
按下它,你会看到轨道上出现一个红色标记,如下所示:
generation analysis
的目的是多次执行一个动作,并查看记忆是否在 unbounded fashion
中增长。钻成搜索,等待图像加载了几秒钟,然后回到主界面。然后再次标记一代。对不同的搜索重复执行此操作。经过一个钻成几个搜索,仪器看起来像这样:
此时,你应该开始怀疑。请注意你钻取的每个搜索的蓝色图表是如何上升的。嗯,那当然不好。但等一下,怎么样 memory warnings?
你知道那些,对吧? Memory warnings
是 iOS 告诉应用程序内存部门事情变得紧张的方式,你需要清除一些内存。
这种增长可能不仅仅是因为你的应用程序; 它可能是一种深藏在记忆中的东西。在指向任何一个之前,先给系统框架和你的应用程序一个清除记忆的机会。
通过选择 Instruments 菜单栏中的 Instrument\Simulate Memory Warning
或 simulator’s
菜单栏中的 Hardware\Simulate Memory Warning
来模拟 memory warning
。你会注意到内存使用量略有下降,或者根本没有下降。当然不会回到它应该的位置。所以在某个地方仍然存在无限的内存增长。
在每次迭代钻取到搜索之后标记生成的原因是你可以看到在每一代之间分配了哪些内存。看看细节面板,你会看到几代人。