iOS 应用性能测试的相关方法、工具及技巧
用户不喜欢等待。他们不关心也不应该关心一个应用初始化的时候需要什么,他们只想尽快地完成他们的任务。你的应用应该几乎是瞬间启动的,其界面应当如丝般顺滑。在充满竞争的软件市场中,应用的性能是关键的优势之一。
作为开发者,我们也希望对我们辛苦开发的 app 感到自豪。
然而,性能优化是一个棘手的问题。大多数的瓶颈是反直觉的。如果没有合适的度量,找出拖慢 app 的原因是非常困难的。
要优化你的 app 的性能,你应该基于数据做决定。在这篇文章中我将会通过度量你的 app 的不同方面的性能,来展示如何得到这个数据。
我将谈及的方面是:
CPU,GPU,内存以及 app 的能源消耗;
响应性;
启动时间;
从你的用户那里收集的性能指标;
让我们开始吧!
CPU,GPU,内存以及能源消耗
分析你的 app 的第一个任务,是找出过度使用 CPU, GPU 或者内存的低效代码。Apple 有一个很棒的工具 Instruments 来完成这个任务:
有4个主要的方面需要重点考虑:
CPU (“Time Profiler” 工具);
GPU (“Core Animation” 工具);
内存使用 (“Allocations” 工具);
电量使用 (“Energy diagnostics” 工具).
关于使用 Instruments 来分析 app 的最佳信息来源就是 WWDC 视频。
有一些入门的精华:
Learning Instruments;
iOS Performance 1, 2, 3;
Improving You App With Instruments;
Advanced Graphics & Animations for iOS Apps;
Profiling In-Depth;
Cocoa Touch Best Practices;
iOS Performance and Power Optimization with Instruments;
Polishing Your App.
响应性
下一个需要测量的重要的东西是 UI 的响应性。触摸的处理发生在主线程。主线程有耗时操作的时候,你的 app 变得反应迟钝。
即使有些操作并不使用 CPU,它们也可能会占用时间。如果主线程有同步调用,测量这些调用耗费的时间。
要测量这个,你可以使用日志。
CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
// Your method
NSUInteger milliseconds = (NSUInteger)((CFAbsoluteTimeGetCurrent() — startTime) * 1000);
NSLog(“Done in %lu ms”, milliseconds);
Viber 的开发者描述了另一种方法。他们有一个特殊的线程用来监视主线程,并监测主线程的阻塞不会超过 400 毫秒。
测试响应性(来自 Viber 关于 NSSpain 的 PPT)
测试响应性(来自Viber关于NSSpain的PPT)
更多信息请参考 PPT原文 (PDF, 7MB)。
https://dl.dropboxusercontent.com/u/3820193/VbierClientUnderTheHood.pdf
使用这个数据来监测耗时太长的调用(400毫秒是一个不错的阈值,你可以读一下 这本书 获取更多信息),然后优化它们或者将其从主线程移出去。
启动时间
下一个需要测量的重要的事情是你的app启动有多快。典型的用户只会在你的app花费 几分钟时间。过长的启动时间会招致失望。
你的app有两种被启动的情况:
冷 启动:你的 app 的进程没有在运行,它现在被操作系统启动。
热 启动:你的 app 被最小化而没有杀死。它是从后台恢复的。
本章节主要讨论冷启动,因为这是更加资源密集的操作。
下图是一个 iOS app 的启动时序。
The Application Startup Phases (from the documentation) 应用启动阶段(来自这篇文档)
1. 测量启动花费的总时间
我们应当测量从 main() 的开头到 applicationDidBecomeActive: 末尾之间花费的时间。
int main(int argc, char * argv[]) {
// Save the initial time for startup
[[StartipTimeMonitor sharedMonitor] appWillStartLoading];
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Your code
// We assume that the app is loaded then the main thread become free
// after this callback is finished.
dispatch_async(dispatch_get_main_queue(), ^{
[[StartipTimeMonitor sharedMonitor] appDidFinishLoading];
});
}
当你引入新特性的时候,确保启动时间不会变得更糟。试着将冷启动时间控制在 1 秒以内。
2. 测量启动时序阶段的时间
通常来说,只知道启动消耗的总时间是不够的。搞清楚启动时序中的哪个阶段拖慢了启动也很重要。
要考虑的最重要的阶段是:
-[AppDelegate application:didFinishLaunchingWithOptions:] — 当启动图(或故事板)显示的时候这个回调被调起。当你的 app从这个方法返回的时候,实际的UI立刻开始加载。
-[UIViewController loadView] — 如果你的app加载一个自定义的 view,这里是 view 初始化的地方。
-[UIViewController viewDidLoad] — view 已经被加载;最终的初始化的时间。
-[AppDelegate applicationDidBecomeActive:]— UI 已经被初始化,但是在这个
回调完成之前UI仍旧被阻塞着。当你的 app 从后台被恢复时,这个方法也会被调用。
如果这些方法中的某些占用了过多的时间,优化它。
3. 测量“压力下”的启动时间
真实世界与典型的测试环境相比有一个重要的不同。
你的 app 在真实世界不是孤立存在的。
用户常常从另一个 app 切换到你的 app。这个“另一个 app”可能非常笨重。因此测量这些情景下的启动时间非常重要,那就是:你的 app 开始启动的同时,另一个笨重的 app 正在切换到后台,并试图保存它的数据。
那样的测试可以发现一些意想不到的结果。先前完全无害的代码,在那种情境下可能会显著地拖慢你的 app。
4. app 已经启动,但仍然不可用
如果你的 app 在已经加载完UI之后并不是立即可用,那么它并没有真正地完成加载。即使 UI 已经加载完毕并且有响应,但仍需要加载一些数据才能准备就绪,把这也算到启动阶段去。
从你的用户那里收集的性能指标
前述的所有测量方法在测试环境都可以使用。这些是必须的,但是并不高效。如果你的 app 很流行,如果你的用户群遍布全球,一些用户的环境可能跟你预期中的相差巨大。
他们可能有不同的:
网络状况;
硬件;
软件(操作系统版本,越狱……);
设备上的可用空间
其他种种
他们也可能有不同的 app 使用方式。
即使你在实验环境中测试的所有指标都处在安全区间,你仍有可能得到带着抱怨的一星评价(“你的 app 太慢!”)。
对此应该做些什么呢?
定义一套性能指标(或 KPI),并从真实用户那里收集数据。你可以利用几乎任意的分析程序包来做这件事。
下面是你可以从用户那里得到的 KPI 的例子:
总的冷启动时间。
总的热启动时间。
启动阶段的启动时间。
从服务器下载必要数据花费的时间。
主线程阻塞超过400毫秒的次数。
内存警告的次数。
FOOMS 的数量。
UI 阻塞或不可用时操作的长度。
分析程序包将允许你把这些值以及设备类型、国家或网络运营商一起,分散存储到片段中。这些可能会让你洞悉用户遇到了什么样的性能问题,以及如何修复它。
结论
正如你看到的一样,性能度量不仅仅是运行 Instruments.app。还有其它有价值的地方值得考虑。
上述的一些方法实现起来简单快捷,另外一些则要求更多的时间和精力。然而,它们将帮助你监控你的app的性能,找出并解决问题,使你的app用起来更加有趣。
iOS 应用性能测试的相关方法、工具及技巧的更多相关文章
- 25个增强iOS应用程序性能的提示和技巧(中级篇)(2)
25个增强iOS应用程序性能的提示和技巧(中级篇)(2) 2013-04-16 14:42 破船之家 beyondvincent 字号:T | T 本文收集了25个关于可以提升程序性能的提示和技巧,分 ...
- 25个增强iOS应用程序性能的提示和技巧--中级篇
25个增强iOS应用程序性能的提示和技巧--中级篇 标签: ios性能优化内存管理 2013-12-13 10:55 738人阅读 评论(0) 收藏 举报 分类: IPhone开发高级系列(34) ...
- iOS开发UI篇—IOS开发中Xcode的一些使用技巧
iOS开发UI篇—IOS开发中Xcode的一些使用技巧 一.快捷键的使用 经常用到的快捷键如下: 新建 shift + cmd + n 新建项目 cmd + n 新建文 ...
- 25个增强iOS应用程序性能的提示和技巧 — 中级篇
本文由破船译自:raywenderlich 转载请注明出处:BeyondVincent的博客 _____________ 在开发iOS应用程序时.让程序具有良好的性能是非常关键的.这也是用户所期望的. ...
- fir.im Weekly - 17 个提升 iOS 开发效率的必备工具
本期 fir.im Weekly 精选了一些iOS 开发工具和动画源码分享,希望每个开发者能专注效率.实用.灵感. iOS开发工具--如何优化ipa包大小 @iOS程序犭袁 推荐了关于"如 ...
- 25个增强iOS应用程序性能的提示和技巧(高级篇)(2)
25个增强iOS应用程序性能的提示和技巧(高级篇)(2) 2013-04-16 14:56 破船之家 beyondvincent 字号:T | T 在开发iOS应用程序时,让程序具有良好的性能是非常关 ...
- 25个增强iOS应用程序性能的提示和技巧(高级篇)(1)
25个增强iOS应用程序性能的提示和技巧(高级篇)(1) 2013-04-16 14:56 破船之家 beyondvincent 字号:T | T 在开发iOS应用程序时,让程序具有良好的性能是非常关 ...
- 25个增强iOS应用程序性能的提示和技巧(中级篇)(3)
25个增强iOS应用程序性能的提示和技巧(中级篇)(3) 2013-04-16 14:42 破船之家 beyondvincent 字号:T | T 本文收集了25个关于可以提升程序性能的提示和技巧,分 ...
- 25个增强iOS应用程序性能的提示和技巧(初级篇)
25个增强iOS应用程序性能的提示和技巧(初级篇) 标签: ios内存管理性能优化 2013-12-13 10:53 916人阅读 评论(0) 收藏 举报 分类: IPhone开发高级系列(34) ...
随机推荐
- [OI笔记] 最长上升子序列与网络流建模
与最长上升子序列相关的网络流问题: 给定一个序列 A[1..n] ,求出 A 的最长上升子序列长度.并且回答下列询问: (1) 如果每个点只能用一次,能从 A 中取出几个最长上升子序列? (2) 如果 ...
- hdu 4452
今天模拟赛的一个模拟题: 每次看到这种题就感觉很繁琐: 这次静下心来写写,感觉还不错!就是很多错误,浪费了一点时间: 代码: #include<cstdio> #include<cs ...
- SSH框架是个怎么回事?
我相信来看这篇文章的童鞋基本上是刚开始入门正在努力找方向的,所以我将尽可能的少涉及旁枝末节及背景知识,力求简明易懂.当然高手们如果在读了小文之后发现了任何错误和不妥,请不吝指正. 直接进入正题.现在我 ...
- 【UVA 11383】 Golden Tiger Claw (KM算法副产物)
Omi, Raymondo, Clay and Kimiko are on new adventure- in search of new Shen Gong Wu. But EvilBoy Geni ...
- <c:if>判断参数是否为空
EL表达式判断字符串是否为空: <c:if test="${empty str}"> str为空</c:if> <c:if test="${ ...
- 控件构造函数需要的AOwner是TComponent,而不是Parent
普通控件都只有一个构造函数,但是这个构造函数却强迫指定AOwner,也就是说,VCL希望将所有控件(至少是所有可视化控件)全部置于它的管理之下.至于到底显示不显示,那是另一个层次的问题.这个问题其实挺 ...
- GridControl控件添加按钮列及在按钮Click事件中得到行数据 zt
在GridControl中添加按钮列的步骤如下: 1. 把列的ColumnEdit属性设置为RepositoryItemButtonEdit 2. 把TextEditStyle属性设置为HideTex ...
- win7下安装load generator
win7下只安装loadrunner load generator 1.点击setup.exe 2.选择“loadrunner 完整安装程序” 3.安装完成所需要的插件,然后重启 4.重新打开安装 ...
- ASP.NET MVC 中将FormCollection与实体间转换方法 (转)
将Action动作中传递的FormCollection转变成对应的实体,可以使用Controller的TryUpdateModel()方法. [HttpPost] public ActionResul ...
- JavaScript---网络编程(4)-Date、Math、Global和自定义对象
本节博客进行Date对象.Math对象.Global对象和自定义对象的用法演示. 首先是一个out.js文件内容(输出到网页中的自定义输出方法): function println(parma){ d ...