软件性能测试理论手札(二)
第二章 操作系统性能计数器及分析方法
性能计数器通常被用来衡量被测系统当前的状况和进行性能测试结果分析。单一的新能计数器通常反映了系统性能的侧面,在进行性能测试结果分析时,一般要多个性能计数器进行分析。本章按照操作系统对性能测试过程中使用到的计数器进行说明。
2.1 Windows性能计数器及其分析
操作系统计数器可用来监控操作系统级别上的系统性能表现。
2.1.1 Window操作系统的主要计数器
Windows操作系统的主要计数器如表2.1所示:
表2-1 Windows操作系统的主要计数器
2.1.2 内存分析方法
内存分析用于判断系统有无遇到内存瓶颈,是否通过增加内存来等手段来提高系统性能表现。
内存分析需要使用表2-1中的Memory和PhysicalDisk类别的计数器。以下是内存分析的主要方法和步骤。
查看Memory\Available Mbytes指标
该指标是描述系统可用内存的直接指标。如果该指标的数据比较小,系统可能出现了内存方面的问题。
注意Pages/sec、Pages Read/sec和Pages Faults/sec的值
windows和linux操作系统提供这三个指标来支持磁盘交换次数的统计,这三个指标直接反映了操作系统进行交换的频度。如果Pages/sec、Pages Faults/sec数值很大而且Pages Read/sec计数值超过5,则可以判断为内存方面的问题
根据Physical Disk计数器的值分析性能瓶颈
如果Pages Read/sec值很低,但%DiskTime和Average Disk Queue Length的值很高,则可能是磁盘瓶颈;如果队列长度增加,但Pages Read/sec并未降低,则是由于内存不足。
2.1.3 处理器分析方法
处理器(CPU)也可能是系统的瓶颈,如下是针对处理器进行分析的步骤:
查看System\%TotalProcessor Time性能计数器的计数值
该计数值用于体现服务器整体的处理器使用率,对多处理器系统来说,该值体现了所有CPU的平均使用率。该值的数值持续超过90%,则说明整个系统面临着处理器方面的瓶颈,需要通过增加处理器来提高性能。
PS:由于操作系统本身的特性,在某些多CPU系统中,该数据本身并不大,但若CPU之间的负载情况极为不均衡,也应该视作系统产生了处理器方面的瓶颈。
查看每个CPU的Processor\%ProcessorTime和Processor\%UserTimes和Processor\%PrivilegedTime
Processor\%User Time是指系统的非核心操作系统消耗的CPU时间,如果该值较大,可以考虑是否通过算法优化等方法来降低该值。如果该服务器是数据库服务器,Processor\%User Time值大的原因很可能是数据库的排序或函数操作消耗了过多的CPU时间,此时可以考虑对数据库系统进行优化。
研究系统处理器瓶颈
查看System\Processor Queue Length计数器的值,当该计数器的值大于CPU数量的总数加1时,说明处理器阻塞。处理器的%Process Time值很高时,一般都伴随着处理器阻塞,但产生处理器阻塞时,Processor\%Process Time计数器的值并不一定很大,此时就需要查看处理器阻塞的原因。
%DPC Time该值越低越好,在多处理器系统中,如果该值大于50%并且Processor\%Process Time值非常高,则考虑加入一个网卡来提高性能
2.1.4 磁盘I|O分析方法
磁盘I|O也是影响系统性能的一个关键因素。如果所分析的计数器指标来自于数据库服务器、文件服务器、流媒体服务器,磁盘I|O更容易成为瓶颈。磁盘I|O的分析方法如下:
计算每磁盘的I|O数
每磁盘的I|O数用来与磁盘的I|O能力进行对比,如果计算得到的每磁盘I|O数超过了磁盘标称的I|O能力,则说明确实存在磁盘的性能瓶颈。表2-3给出了每磁盘I|O的计算方法。
表2-3 每磁盘I|O的计算方法
与Processor\Privileged Time合并分析
如果Physical Disk计数器中,只有%Disk Time值较大,其他值都比较合适,则硬盘可能会是瓶颈。若几个值都比较大,且数值持续超过80%,则可能是内存泄漏。
根据Disk Sec/Transfer进行分析
一般来说,定义Transfer数值小于15毫秒为优秀,介于15~30毫秒之间为良好,在30~60毫秒之间为可以接受,超过60毫秒则需要考虑更换硬盘或硬盘的RAID方式了
2.2 UNIX/LINUX性能计数器及其分析
2.2.1 UNIX/LINUX操作系统的主要计数器
UNIX/LINUX操作系统的主要计数器表2-2所示。
表2-2 UNIX/LINUX操作系统的主要计数器
PS:LINUX操作系统的命令与UNIX稍有差别。UNIX系统的主要计数器监控命令是vmstat、iostat、top、sar、和seg(图形方式,需要XServer支持);而在Linux中,没有iostat命令,iostat可以监控的计数器包含在vmstat命令中,可以通过参数控制。
2.3 Android 系统性能计数机器分析
2.3.1 Linux 内核
Android是基于Linux2.6内核,其核心系统服务如安全性、内存管理、进程管理、网路协议以及驱动模型都依赖于Linux内核。内核”指的是一个提供硬件抽象层、磁盘及文件系统控制、多任务等功能的系统软件。一个内核不是一套完整的操作系统。内核组成如下图:
2.3.1.1系统调用接口
SCI 层提供了某些机制执行从用户空间到内核的函数调用。正如前面讨论的一样,这个接口依赖于体系结构,甚至在相同的处理器家族内也是如此。SCI 实际上是一个非常有用的函数调用多路复用和多路分解服务。在 ./linux/kernel 中您可以找到 SCI 的实现,并在 ./linux/arch 中找到依赖于体系结构的部分。有关这个组件的更详细信息可以在 参考资料 一节中找到。
2.3.1.2进程管理
进程管理的重点是进程的执行。在内核中,这些进程称为线程,代表了单独的处理器虚拟化(线程代码、数据、堆栈和 CPU 寄存器)。在用户空间,通常使用进程 这个术语,不过 Linux 实现并没有区分这两个概念(进程和线程)。内核通过 SCI 提供了一个应用程序编程接口(API)来创建一个新进程(fork、exec 或 Portable Operating System Interface[POSIX] 函数),停止进程(kill、exit),并在它们之间进行通信和同步(signal 或者 POSIX 机制)。
进程管理还包括处理活动进程之间共享 CPU 的需求。内核实现了一种新型的调度算法,不管有多少个线程在竞争 CPU,这种算法都可以在固定时间内进行操作。这种算法就称为 O(1) 调度程序,这个名字就表示它调度多个线程所使用的时间和调度一个线程所使用的时间是相同的。 O(1) 调度程序也可以支持多处理器(称为对称多处理器或 SMP)。您可以在 ./linux/kernel 中找到进程管理的源代码,在 ./linux/arch 中可以找到依赖于体系结构的源代码。在 参考资料 一节中可以了解有关这个算法的更多内容。
2.3.1.3内存管理
内核所管理的另外一个重要资源是内存。为了提高效率,如果由硬件管理虚拟内存,内存是按照所谓的内存页 方式进行管理的(对于大部分体系结构来说都是 4KB)。Linux 包括了管理可用内存的方式,以及物理和虚拟映射所使用的硬件机制。
不过内存管理要管理的可不止 4KB 缓冲区。Linux 提供了对 4KB 缓冲区的抽象,例如 slab 分配器。这种内存管理模式使用 4KB 缓冲区为基数,然后从中分配结构,并跟踪内存页使用情况,比如哪些内存页是满的,哪些页面没有完全使用,哪些页面为空。这样就允许该模式根据系统需要来动态调整内存使用。
为了支持多个用户使用内存,有时会出现可用内存被消耗光的情况。由于这个原因,页面可以移出内存并放入磁盘中。这个过程称为交换,因为页面会被从内存交换到硬盘上。内存管理的源代码可以在 ./linux/mm 中找到。
2.3.1.4虚拟文件系统
虚拟文件系统(VFS)是 Linux 内核中非常有用的一个方面,因为它为文件系统提供了一个通用的接口抽象。VFS 在 SCI 和内核所支持的文件系统之间提供了一个交换层,如下图
在 VFS 上面,是对诸如 open、close、read 和 write 之类的函数的一个通用 API 抽象。在 VFS 下面是文件系统抽象,它定义了上层函数的实现方式。它们是给定文件系统(超过 50 个)的插件。文件系统的源代码可以在 ./linux/fs 中找到。
文件系统层之下是缓冲区缓存,它为文件系统层提供了一个通用函数集(与具体文件系统无关)。这个缓存层通过将数据保留一段时间(或者随即预先读取数据以便在需要是就可用)优化了对物理设备的访问。缓冲区缓存之下是设备驱动程序,它实现了特定物理设备的接口。
2.3.1.5网络堆栈
网络堆栈在设计上遵循模拟协议本身的分层体系结构。回想一下,Internet Protocol (IP) 是传输协议(通常称为传输控制协议或 TCP)下面的核心网络层协议。TCP 上面是 socket 层,它是通过 SCI 进行调用的。
socket 层是网络子系统的标准 API,它为各种网络协议提供了一个用户接口。从原始帧访问到 IP 协议数据单元(PDU),再到 TCP 和 User Datagram Protocol (UDP),socket 层提供了一种标准化的方法来管理连接,并在各个终点之间移动数据。内核中网络源代码可以在 ./linux/net 中找到。
2.3.1.6设备驱动程序
Linux 内核中有大量代码都在设备驱动程序中,它们能够运转特定的硬件设备。Linux 源码树提供了一个驱动程序子目录,这个目录又进一步划分为各种支持设备,例如 Bluetooth、I2C、serial 等。设备驱动程序的代码可以在 ./linux/drivers 中找到。
2.3.1.7 依赖体系结构的代码
尽管 Linux 很大程度上独立于所运行的体系结构,但是有些元素则必须考虑体系结构才能正常操作并实现更高效率。./linux/arch 子目录定义了内核源代码中依赖于体系结构的部分,其中包含了各种特定于体系结构的子目录(共同组成了 BSP)。对于一个典型的桌面系统来说,使用的是 i386 目录。每个体系结构子目录都包含了很多其他子目录,每个子目录都关注内核中的一个特定方面,例如引导、内核、内存管理等。这些依赖体系结构的代码可以在 ./linux/arch 中找到。
2.3.2 安卓系统性能分析
CPU
CPU的快慢直接决定了手机的反应速度,但是速度越快的CPU耗电量就越大。目前主流的智能手机CPU有以下几种:
德州仪器
优点:低频高能且耗电量较少,高端智能机必备CPU
缺点:价格不菲,对应的手机价格也很高,OMAP3系列GPU性能不高,但OMAP4系列有了明显改善,数据处理能力较弱。
Intel
优点:CPU主频高,速度快
缺点:耗电、每频率性能较低
高通
优点:主频高,数据处理性能表现出色,拥有最广泛的产品路线图,支持包括智能手机、平板电脑、智能电视等各类终端,可以支持所有主流移动操作系统,支持3G/4G网络制式
缺点:图形处理能力较弱,功能耗较大。
三星
优点:耗电量低、三星蜂鸟S5PC110单核最强,DSP搭配较好,GPU性能较强
缺点:三星猎户双核发热问题大,搭载MALI400GPU构图单一,兼容性不强
Marvell
优点:很好继承和发挥了PXA的性能
缺点:功耗大
英伟达
优点:最早上市的双核CPU,搭载的GeforceULP面积小,性能强,功耗较低
缺点:Tegra2因为功耗问题去掉了NEON,导致视频解码问题大,支持硬解格式少
华为
优点:是2012年业界体积最小的四核A9架构处理器。他是一款高性能CPU,是华为自主设计
缺点:性能不了解
Memory
原文参考:http://www.wtoutiao.com/p/1fcxFYj.html
Android设备出厂以后,java虚拟机对单个应用的最大内存分配就确定下来了,超出这个值就会OOM。这个属性值是定义在/system/build.prop文件中的
dalvik.vm.heapstartsize=8m
它表示堆分配的初始大小,它会影响到整个系统对RAM的使用程度,和第一次使用应用时的流畅程度。
它值越小,系统ram消耗越慢,但一些较大应用一开始不够用,需要调用gc和堆调整策略,导致应用反应较慢。它值越大,这个值越大系统ram消耗越快,但是应用更流畅。dalvik.vm.heapgrowthlimit=64m // 单个应用可用最大内存
主要对应的是这个值,它表示单个进程内存被限定在64m,即程序运行过程中实际只能使用64m内存,超出就会报OOM。(仅仅针对dalvik堆,不包括native堆)dalvik.vm.heapsize=384m//heapsize参数表示单个进程可用的最大内存,但如果存在heapgrowthlimit参数,则以heapgrowthlimit为准.
heapsize表示不受控情况下的极限堆,表示单个虚拟机或单个进程可用的最大内存。而android上的应用是带有独立虚拟机的,也就是每开一个应用就会打开一个独立的虚拟机(这样设计就会在单个程序崩溃的情况下不会导致整个系统的崩溃)。
注意:在设置了heapgrowthlimit的情况下,单个进程可用最大内存为heapgrowthlimit值。在android开发中,如果要使用大堆,需要在manifest中指定android:largeHeap为true,这样dvmheap最大可达heapsize。不同设备,这些个值可以不一样。一般地,厂家针对设备的配置情况都会适当的修改/system/build.prop文件来调高这个值。随着设备硬件性能的不断提升,从最早的16M限制(G1手机)到后来的24m,32m,64m等,都遵循Android框架对每个应用的最小内存大小限制。
通过代码查看每个进程可用的最大内存,即heapgrowthlimit值:
ActivityManager activityManager = (ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE);
int memClass = activityManager.getMemoryClass();//64,以m为单位Disk
长期使用 Android 手机必将产生大量的磁盘碎片,而磁盘碎片将会降低磁盘的读写性能,从而影响系统流畅度。但是磁盘碎片是否能对磁盘的读写性能造成了很大影响,以至于影响系统流畅度尚未可知,且暂时也没有发现可以进行尝试的潜在优化点。
Step 0:磁盘与系统流畅度的关系
Android 在使用网络的最佳实践是使用3级缓存的设计来提升系统的流畅度并节省流量:CPU 首先尝试从内存中加载图片,若此时图片存在在内存中则加载成功,否则内存会从磁盘中加载图片,若此时图片存在在磁盘中则加载成功,否则磁盘会最终向网络中下载图片。
其实上述的执行逻辑,也就解释了磁盘是如何影响系统流畅度的:对于系统流畅度(其实也是各个应用的流畅度)影响最直接的就是 CPU 的执行效率,但是如果这个过程中内存、磁盘以及网络的读写速度如果跟不上 CPU 的执行效率的话,就会造成 CPU 在处理任务的时候需要花费时间等待数据,从而影响了流畅度。
所以第一个问题就弄清楚了:磁盘的读写速度的降低会使得系统流畅度变差!那么,我们要分析的问题就转化成:磁盘在长期使用的过程中,其读写速度会不会降低。
Step 1:弄清 Android 磁盘的读写机制
通过资料查阅,目前,Android 手机大多采用 NAND Flash 架构的闪存卡来存储内容。NAND Flash 的内部存储单位从小到大依次为:Page、Block、Plane、Die,而一个 Device 上可以封装若干个 Die。下图就是一个 NAND Flash 组成结构的示意图。
为了方便理解,针对一个 Die,我们再抽象一下,Page、Block、Plane、Die 的关系如下图所示。
虽然NAND Flash 的优点多多,但是为了延长驱动器的寿命,它的读写操作均是以 Page 为单位进行的,但擦除操作却是按Block 为单位进行的。
由于有大量的读写操作,于是我们的 NAND Flash 制定了如下的读写规则:
删除数据时,芯片将标记这些 Page 为闲置状态,但并不会立马执行擦除操作。
写入数据时,如果目前磁盘剩余空间充足,则由芯片指定 Block 后直接按 Page 为单位进行写入即可。
写入数据时,如果目前磁盘剩余空间不足,为了获得足够的空间,磁盘先将某块Block 的内容读至缓存,然后再在该 Block 上进行擦除操作,最后将新内容与原先内容一起写入至该 Block。
那么问题来了!假如现在我要向磁盘中写入一张图片的数据,这个图片的数据大小刚好为一个 Page。最坏的情况就是,内存中恰好只有一个 Block 恰好有一个 Page 的无效数据可以擦除。为了存下这张图片,于是主控就把这个 Block 的所有数据读至缓存,擦除Block上的内容,再向缓存中加上这个4KB 新数据后最后写回 Block 中。
我的天啊,其实想存储的就是1个 Page 的图片内容,但是实际上确造成了整个 Block 的内容都被重新写入,同时原本简单一步搞定的事情被还被分成了前后四步执行(闪存读取、缓存改、闪存擦除、闪存写入)造成延迟大大增加,速度变慢。这就是传说中的“写入放大”(Write Amplification)问题。而“写入放大”也说明了磁盘在长期使用的过程中,其读写速度(尤其是写入速度)会存在降低的现象。
Step 2:解决“写入放大”问题的技术——TRIM
使用TRIM 技术解决 “写入放大”。
TRIM 是一条 ATA 指令,由操作系统发送给闪存主控制器,告诉它哪些数据占的地址是“无效”的。在 TRIM 的帮助下,闪存主控制器就可以提前知道哪些 Page 是“无效”的,便可以在适当的时机做出优化,从而改善性能。这里要强调下,TRIM 只是条指令,让操作系统告诉闪存主控制器这个 Page 已经“无效”就算完了,并没有任何其它多余的操作。在测试的过程中,我们发现 TRIM 的触发需要操作系统、驱动程序以及闪存主控三者都支持才能真正意义上实现。例如:
操作系统不支持的情况:Android 4.3以下均不支持
闪存主控不支持的情况:Samsung Galaxy Nexus(I9250)所选用的闪存不支持
基于 TRIM 技术,目前常见有两种方案可以解决“写入放大”的问题:
1. discard 选项。该方案将在挂载 ext4 分区时加上 discard 选项,此后操作系统在执行每一个磁盘操作时同时都会执行 TRIM 指令。该方案的优点是总体耗时短,但影响会到删除文件时的性能。
2. fstrim 命令。该方案将选择合适的时机对整个分区执行 TRIM 操作。相对于方案一,该方案总体耗时较长,但不会影响正常操作时的磁盘性能。
不得不说,如果从用户的角度出发,还是 FSTRIM 的方法更靠谱一些,但如何寻找合适的 TRIM 时机就是一个比较讲究的问题了。
Step 3:TRIM 在 Android 中的实现
根据前面的分析,我们不难理解在 Android 中的 TRIM 选择通过 fstrim 命令的方式进行实现。那么,Google 又是如何设计触发TRIM的时机呢?
通过走读 Android 源码(AOSP 4.4.4),可以了解到 Android 通过系统服务 IdleMaintenanceService 来进行系统状态监控并决定何时触发 TRIM。根据 IdleMaintenanceService.java 源码,我们绘制了 fstrim 的触发示意图如下:
注释:
有/无操作:距屏幕熄灭||屏保启动已超过71分钟
是/否电量充足:维护期20%,非维护期(充电状态30%,非充电状态80%)
是/否维护超时:启动维护已超过71分钟
是/否已到维护期:据上次启动维护超过1天
Step 4:分析闪存碎片及 TRIM 对磁盘 I/O 性能的影响
了解了这么多技术背景,那我们通过测试数据分析闪存碎片和 TRIM 对磁盘 I/O 性能的影响。根据测试目的,具体的测试设置如下:
测试目的:
评估闪存碎片和TRIM对磁盘 I/O 性能的影响
测试方案:
测试对象:LG Nexus 5 with cm-11-20140805-SNAPSHOT-M9-hammerhead
测试步骤:
1. 重新刷机,使用 Bonnie++ 测试 SD 卡目录的 I/O 性能;
2. 模拟长期使用 SD 卡的过程(期间需要避免TRIM触发),使用 Bonnie++ 测试 SD 卡目录的 I/O 性能;
3. 主动触发 TRIM,使用Bonnie++ 测试 SD 卡目录的 I/O 性能。
备注:
1. 模拟长期使用 SD 卡的过程的方法:开发专用的测试应用,该应用将向 SD 卡目录不停写入大小随机的文件,当 SD 卡剩余空间不足时将删除所写入的文件,然后继续上述操作直到应用退出。
2. 避免 TRIM 触发的方法:根据 Android 的触发过程分析,只需设置屏幕常亮并即可避免 TRIM 的触发。
测试数据:
数据解读:
1. 通过反复擦写 SD 卡,可以发现 SD 卡的 I/O 效率指标均存在一定幅度的下滑,其中反映磁盘空间分配性能及文件数据写回性能的指标下滑明显;
2. Sequential Output-Block 可以反映分配磁盘文件空间的效率,经反复擦写 SD 卡后,该效率降低至原始值的15-20%,应该是大量的磁盘闲置数据块造成的影响;
3. Sequential Output-Rewrite 可以反映文件系统缓存和数据传输的速度,经反复擦写 SD 卡制造闲置数据块后,该效率降低至原始值的50%。
4. 主动调用 TRIM 后,可以发现 SD 卡的 I/O 效率指标均恢复至接近原始值水平(但仍未完全达到初始状态的水平)。
测试结论:
1. 在 TRIM 无效的情况下,长期使用 SD 卡,磁盘写入速度会受到明显影响;
2. TRIM 对因闲置数据块造成的 I/O 性能下降有一定的恢复作用;
3. 大量的读写操作对 SD 卡造成了一定量的不可恢复的损耗。
Step 5:FSTRIM 系统自动触发测试
完成了上面的工作,不由得让我们大吃一鲸:原来 TRIM 对 SD 卡的读写速度的维护如此重要!前面也说到,Android 选择 FSTRIM 方案的来实现 TRIM,那么 Android 所设计的 FSTRIM 触发时机有没有什么问题呢?
根据Android 系统的设定,FSTRIM 预期是每隔24小时触发一次。所以,接下来我们需要评估一下,FSTRIM 能否依据上述设定成功被系统触发。
测试目的:
分析FSTRIM 能否被按时被系统触发
测试方案:
测试对象:2台 Samsung Galaxy Nexus 及2台 LG Nexus 5
测试步骤:
1. 刷机后,安装常用应用并启动(均无SIM卡,其中1台设备开启 Wifi,另1台设备关闭 Wifi);
2. 进行 Log 记录;
3. 强制执行一次 FSTRIM;
4. 灭屏等待30小时左右,提取Log 记录进行分析。
测试数据:
开启WiFi |
关闭WiFi |
|
Samsung Galaxy Nexus |
启动FSTRIM 1次 |
启动FSTRIM 1次 |
LG Nexus 5 |
未启动FSTRIM |
启动FSTRIM 1次 |
据解读:
1. FSTRIM 大多数情况会被自动触发,但也存在无法触发的情况;
2. 根据 FSTRIM 的触发逻辑,是否开启 WIFI 对 FSTRIM 的影响主要是有无推送消息(影响灭屏条件)以及不同的耗电。
测试结论:
测试数据显示 FSTRIM 大多数情况会被自动触发,但也存在无法触发的情况。可能的原因是:FSTRIM对电量的要求略高,所以一旦发生意外情况(如应用的 PUSH 消息)终止了计划 FSTRIM 的执行之后,很长时间之内都无法再满足 FSTRIM 的启动条件。
所以,如需提高其触发频率,我们可以考虑降低触发条件中对电量的要求。
2.4 IOS 系统性能分析
2.4.1 内存优化
该段内容转载:http://www.2cto.com/kf/201505/401059.html
1. 用ARC管理内存
ARC(AutomaticReferenceCounting, 自动引用计数)和iOS5一起发布,它避免了最常见的也就是经常是由于我们忘记释放内存所造成的内存泄露。它自动为你管理retain和release的过程,所以你就不必去手动干预了。忘掉代码段结尾的release简直像记得吃饭一样简单。而ARC会自动在底层为你做这些工作。除了帮你避免内存泄露,ARC还可以帮你提高性能,它能保证释放掉不再需要的对象的内存。
2. 在正确的地方使用 reuseIdentifier
一个开发中常见的错误就是没有给UITableViewCells, UICollectionViewCells,甚至是UITableViewHeaderFooterViews设置正确的reuseIdentifier。
为了性能最优化,table view用`tableView:cellForRowAtIndexPath:`为rows分配cells的时候,它的数据应该重用自UITableViewCell。一个table view维持一个队列的数据可重用的UITableViewCell对象。
不使用reuseIdentifier的话,每显示一行table view就不得不设置全新的cell。这对性能的影响可是相当大的,尤其会使app的滚动体验大打折扣。
自iOS6起,除了UICollectionView的cells和补充views,你也应该在header和footerviews中使用reuseIdentifiers。
想要使用reuseIdentifiers的话,在一个table view中添加一个新的cell时在data source object中添加这个方法:
staticNSString*CellIdentifier = @"Cell";
UITableViewCell*cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierforIndexPath:indexPath];
这个方法把那些已经存在的cell从队列中排除,或者在必要时使用先前注册的nib或者class创造新的cell。如果没有可重用的cell,你也没有注册一个class或者nib的话,这个方法返回nil。
3.尽量把views设置为透明
如果你有透明的Views你应该设置它们的opaque属性为YES。
原因是这会使系统用一个最优的方式渲染这些views。这个简单的属性在IB或者代码里都可以设定。
Apple的文档对于为图片设置透明属性的描述是:
(opaque)这个属性给渲染系统提供了一个如何处理这个view的提示。如果设为YES,渲染系统就认为这个view是完全不透明的,这使得渲染系统优化一些渲染过程和提高性能。如果设置为NO,渲染系统正常地和其它内容组成这个View。默认值是YES。
在相对比较静止的画面中,设置这个属性不会有太大影响。然而当这个view嵌在scroll view里边,或者是一个复杂动画的一部分,不设置这个属性的话会在很大程度上影响app的性能。
你可以在模拟器中用Debug\Color Blended Layers选项来发现哪些view没有被设置为opaque。目标就是,能设为opaque的就全设为opaque!
4.避免过于庞大的XIB
iOS5中加入的Storyboards(分镜)正在快速取代XIB。然而XIB在一些场景中仍然很有用。比如你的app需要适应iOS5之前的设备,或者你有一个自定义的可重用的view,你就不可避免地要用到他们。
如果你不得不XIB的话,使他们尽量简单。尝试为每个Controller配置一个单独的XIB,尽可能把一个View Controller的view层次结构分散到单独的XIB中去。
需要注意的是,当你加载一个XIB的时候所有内容都被放在了内存里,包括任何图片。如果有一个不会即刻用到的view,你这就是在浪费宝贵的内存资源了。Storyboards就是另一码事儿了,storyboard仅在需要时实例化一个view controller.
当家在XIB是,所有图片都被chache,如果你在做OS X开发的话,声音文件也是。Apple在相关文档中的记述是:
当你加载一个引用了图片或者声音资源的nib时,nib加载代码会把图片和声音文件写进内存。在OS X中,图片和声音资源被缓存在named cache中以便将来用到时获取。在iOS中,仅图片资源会被存进named caches。取决于你所在的平台,使用NSImage 或UIImage的`imageNamed:`方法来获取图片资源。
5.不要阻塞主线程
永远不要使主线程承担过多。因为UIKit在主线程上做所有工作,渲染,管理触摸反应,回应输入等都需要在它上面完成。
一直使用主线程的风险就是如果你的代码真的block了主线程,你的app会失去反应。
大部分阻碍主进程的情形是你的app在做一些牵涉到读写外部资源的I/O操作,比如存储或者网络。
你可以使用`NSURLConnection`异步地做网络操作:
+(void)sendAsynchronousRequest:(NSURLRequest *)requestqueue:(NSOperationQueue*)queue completionHandler:(void (^)(NSURLResponse*,NSData*, NSError*))handler
或者使用像AFNetworking这样的框架来异步地做这些操作。
如果你需要做其它类型的需要耗费巨大资源的操作(比如时间敏感的计算或者存储读写)那就用Grand Central Dispatch,或者NSOperation和 NSOperationQueues.
下面代码是使用GCD的模板
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
//switch to a background thread and perform your expensive operation
dispatch_async(dispatch_get_main_queue(),^{
//switch back to the main thread to update your UI
});
});
发现代码中有一个嵌套的`dispatch_async`吗?这是因为任何UIKit相关的代码需要在主线程上进行。
6. 在Image Views中调整图片大小
如果要在`UIImageView`中显示一个来自bundle的图片,你应保证图片的大小和UIImageView的大小相同。在运行中缩放图片是很耗费资源的,特别是`UIImageView`嵌套在`UIScrollView`中的情况下。
如果图片是从远端服务加载的你不能控制图片大小,比如在下载前调整到合适大小的话,你可以在下载完成后,最好是用background thread,缩放一次,然后在UIImageView中使用缩放后的图片。
7. 选择正确的Collection
学会选择对业务场景最合适的类或者对象是写出能效高的代码的基础。当处理collections时这句话尤其正确。
一些常见collection的总结:
·Arrays: 有序的一组值。使用index来lookup很快,使用value lookup很慢,插入/删除很慢。
·Dictionaries: 存储键值对。用键来查找比较快。
·Sets: 无序的一组值。用值来查找很快,插入/删除很快。
8. 打开gzip压缩
大量app依赖于远端资源和第三方API,你可能会开发一个需要从远端下载XML, JSON, HTML或者其它格式的app。
问题是我们的目标是移动设备,因此你就不能指望网络状况有多好。一个用户现在还在edge网络,下一分钟可能就切换到了3G。不论什么场景,你肯定不想让你的用户等太长时间。
减小文档的一个方式就是在服务端和你的app中打开gzip。这对于文字这种能有更高压缩率的数据来说会有更显著的效用。
好消息是,iOS已经在NSURLConnection中默认支持了gzip压缩,当然AFNetworking这些基于它的框架亦然。像Google App Engine这些云服务提供者也已经支持了压缩输出。
9. 重用和延迟加载(lazy load) Views
更多的view意味着更多的渲染,也就是更多的CPU和内存消耗,对于那种嵌套了很多view在UIScrollView里边的app更是如此。
这里我们用到的技巧就是模仿`UITableView`和`UICollectionView`的操作:不要一次创建所有的subview,而是当需要时才创建,当它们完成了使命,把他们放进一个可重用的队列中。
这样的话你就只需要在滚动发生时创建你的views,避免了不划算的内存分配。
创建views的能效问题也适用于你app的其它方面。想象一下一个用户点击一个按钮的时候需要呈现一个view的场景。有两种实现方法:
1.创建并隐藏这个view当这个screen加载的时候,当需要时显示它;
2.当需要时才创建并展示。
每个方案都有其优缺点。用第一种方案的话因为你需要一开始就创建一个view并保持它直到不再使用,这就会更加消耗内存。然而这也会使你的app操作更敏感因为当用户点击按钮的时候它只需要改变一下这个view的可见性。
第二种方案则相反-消耗更少内存,但是会在点击按钮的时候比第一种稍显卡顿。
10. Cache
一个极好的原则就是,缓存所需要的,也就是那些不大可能改变但是需要经常读取的东西。
我们能缓存些什么呢?一些选项是,远端服务器的响应,图片,甚至计算结果,比如UITableView的行高。
NSURLConnection默认会缓存资源在内存或者存储中根据它所加载的HTTP Headers。你甚至可以手动创建一个NSURLRequest然后使它只加载缓存的值。
下面是一个可用的代码段,你可以可以用它去为一个基本不会改变的图片创建一个NSURLRequest并缓存它:
+(NSMutableURLRequest *)imageRequestWithURL:(NSURL *)url {
NSMutableURLRequest*request = [NSMutableURLRequest requestWithURL:url];
request.cachePolicy= NSURLRequestReturnCacheDataElseLoad;// this will make sure the request alwaysreturns the cached image
request.HTTPShouldHandleCookies= NO;
request.HTTPShouldUsePipelining= YES;
[requestaddValue:@"image/*"forHTTPHeaderField:@"Accept"];
returnrequest;
}
注意你可以通过 NSURLConnection 获取一个URL request, AFNetworking也一样的。这样你就不必为采用这条tip而改变所有的networking代码了。
如果你需要缓存其它不是HTTP Request的东西,你可以用NSCache。
NSCache和NSDictionary类似,不同的是系统回收内存的时候它会自动删掉它的内容。
11.权衡渲染方法
在iOS中可以有很多方法做出漂亮的按钮。你可以用整幅的图片,可调大小的图片,uozhe可以用CALayer,CoreGraphics甚至OpenGL来画它们。
当然每个不同的解决方法都有不同的复杂程度和相应的性能。
简单来说,就是用事先渲染好的图片更快一些,因为如此一来iOS就免去了创建一个图片再画东西上去然后显示在屏幕上的程序。问题是你需要把所有你需要用到的图片放到app的bundle里面,这样就增加了体积–这就是使用可变大小的图片更好的地方了:你可以省去一些不必要的空间,也不需要再为不同的元素(比如按钮)来做不同的图。
然而,使用图片也意味着你失去了使用代码调整图片的机动性,你需要一遍又一遍不断地重做他们,这样就很浪费时间了,而且你如果要做一个动画效果,虽然每幅图只是一些细节的变化你就需要很多的图片造成bundle大小的不断增大。
总得来说,你需要权衡一下利弊,到底是要性能能还是要bundle保持合适的大小。
12.处理内存警告
一旦系统内存过低,iOS会通知所有运行中app。在官方文档中是这样记述:
如果你的app收到了内存警告,它就需要尽可能释放更多的内存。最佳方式是移除对缓存,图片object和其他一些可以重创建的objects的strong references.
幸运的是,UIKit提供了几种收集低内存警告的方法:
· 在appdelegate中使用`applicationDidReceiveMemoryWarning:`的方法
· 在你的自定义UIViewController的子类(subclass)中覆盖`didReceiveMemoryWarning`
· 注册并接收 UIApplicationDidReceiveMemoryWarningNotification的通知
一旦收到这类通知,你就需要释放任何不必要的内存使用。
例如,UIViewController的默认行为是移除一些不可见的view,它的一些子类则可以补充这个方法,删掉一些额外的数据结构。一个有图片缓存的app可以移除不在屏幕上显示的图片。
这样对内存警报的处理是很必要的,若不重视,你的app就可能被系统杀掉。
然而,当你一定要确认你所选择的object是可以被重现创建的来释放内存。一定要在开发中用模拟器中的内存提醒模拟去测试一下。
13.重用大开销对象
一些objects的初始化很慢,比如NSDateFormatter和NSCalendar。然而,你又不可避免地需要使用它们,比如从JSON或者XML中解析数据。
想要避免使用这个对象的瓶颈你就需要重用他们,可以通过添加属性到你的class里或者创建静态变量来实现。
注意如果你要选择第二种方法,对象会在你的app运行时一直存在于内存中,和单例(singleton)很相似。
下面的代码说明了使用一个属性来延迟加载一个date formatter. 第一次调用时它会创建一个新的实例,以后的调用则将返回已经创建的实例:
//in your .h or inside a class extension
@property(nonatomic, strong) NSDateFormatter *formatter;
//inside the implementation (.m)
//When you need, just use self.formatter
-(NSDateFormatter *)formatter {
if(!_formatter) {
_formatter= [[NSDateFormatter alloc] init];
_formatter.dateFormat= @"EEE MMM dd HH:mm:ss Z yyyy";// twitter date format
}
return_formatter;
}
还需要注意的是,其实设置一个NSDateFormatter的速度差不多是和创建新的一样慢的!所以如果你的app需要经常进行日期格式处理的话,你会从这个方法中得到不小的性能提升。
14. 使用Sprite Sheets
Spritesheet可以让渲染速度加快,甚至比标准的屏幕渲染方法节省内存。
15.避免反复处理数据
许多应用需要从服务器加载功能所需的常为JSON或者XML格式的数据。在服务器端和客户端使用相同的数据结构很重要。在内存中操作数据使它们满足你的数据结构是开销很大的。
比如你需要数据来展示一个table view,最好直接从服务器取array结构的数据以避免额外的中间数据结构改变。
类似的,如果需要从特定key中取数据,那么就使用键值对的dictionary。
16.选择正确的数据格式
从app和网络服务间传输数据有很多方案,最常见的就是JSON和XML。你需要选择对你的app来说最合适的一个。
解析JSON会比XML更快一些,JSON也通常更小更便于传输。从iOS5起有了官方内建的JSON deserialization就更加方便使用了。
但是XML也有XML的好处,比如使用SAX来解析XML就像解析本地文件一样,你不需像解析json一样等到整个文档下载完成才开始解析。当你处理很大的数据的时候就会极大地减低内存消耗和增加性能。
17.正确设定背景图片
在View里放背景图片就像很多其它iOS编程一样有很多方法:
使用UIColor的 colorWithPatternImage来设置背景色;
在view中添加一个UIImageView作为一个子View。
如果你使用全画幅的背景图,你就必须使用UIImageView因为UIColor的colorWithPatternImage是用来创建小的重复的图片作为背景的。这种情形下使用UIImageView可以节约不少的内存:
//You could also achieve the same result in Interface Builder
UIImageView*backgroundView = [[UIImageView alloc] initWithImage:[UIImageimageNamed:@"background"]];
[self.viewaddSubview:backgroundView];
如果你用小图平铺来创建背景,你就需要用UIColor的colorWithPatternImage来做了,它会更快地渲染也不会花费很多内存:
self.view.backgroundColor= [UIColor colorWithPatternImage:[UIImage imageNamed:@"background"]];
18. 减少使用Web特性
UIWebView很有用,用它来展示网页内容或者创建UIKit很难做到的动画效果是很简单的一件事。
但是你可能有注意到UIWebView并不像驱动Safari的那么快。这是由于以JIT compilation为特色的Webkit的Nitro Engine的限制。
所以想要更高的性能你就要调整下你的HTML了。第一件要做的事就是尽可能移除不必要的javascript,避免使用过大的框架。能只用原生js就更好了。
另外,尽可能异步加载例如用户行为统计script这种不影响页面表达的javascript。
最后,永远要注意你使用的图片,保证图片的符合你使用的大小。使用Sprite sheet提高加载速度和节约内存。
19. 设定Shadow Path
如何在一个View或者一个layer上加一个shadow呢,QuartzCore框架是很多开发者的选择:
#import
//Somewhere later ...
UIView*view = [[UIView alloc] init];
//Setup the shadow ...
view.layer.shadowOffset= CGSizeMake(-1.0f, 1.0f);
view.layer.shadowRadius= 5.0f;
view.layer.shadowOpacity= 0.6;
看起来很简单,对吧。可是,坏消息是使用这个方法也有它的问题… Core Animation不得不先在后台得出你的图形并加好阴影然后才渲染,这开销是很大的。
使用shadowPath的话就避免了这个问题:
view.layer.shadowPath= [[UIBezierPath bezierPathWithRect:view.bounds] CGPath];
使用shadowpath的话iOS就不必每次都计算如何渲染,它使用一个预先计算好的路径。但问题是自己计算path的话可能在某些View中比较困难,且每当view的frame变化的时候你都需要去updateshadow path.
20. 优化Table View
Tableview需要有很好的滚动性能,不然用户会在滚动过程中发现动画的瑕疵。
为了保证tableview平滑滚动,确保你采取了以下的措施:
· 正确使用`reuseIdentifier`来重用cells
· 尽量使所有的view opaque,包括cell自身
· 避免渐变,图片缩放,后台选人
· 缓存行高
· 如果cell内现实的内容来自web,使用异步加载,缓存请求结果
· 使用`shadowPath`来画阴影
· 减少subviews的数量
· 尽量不适用`cellForRowAtIndexPath:`,如果你需要用到它,只用一次然后缓存结果
· 使用正确的数据结构来存储数据
· 使用`rowHeight`,`sectionFooterHeight`和 `sectionHeaderHeight`来设定固定的高,不要请求delegate
21.选择正确的数据存储选项
当存储大块数据时你会怎么做?
你有很多选择,比如:
· 使用`NSUerDefaults`
· 使用XML,JSON, 或者 plist
· 使用NSCoding存档
· 使用类似SQLite的本地SQL数据库
· 使用Core Data
NSUserDefaults的问题是什么?虽然它很nice也很便捷,但是它只适用于小数据,比如一些简单的布尔型的设置选项,再大点你就要考虑其它方式了
XML这种结构化档案呢?总体来说,你需要读取整个文件到内存里去解析,这样是很不经济的。使用SAX又是一个很麻烦的事情。
NSCoding?不幸的是,它也需要读写文件,所以也有以上问题。
在这种应用场景下,使用SQLite 或者 Core Data比较好。使用这些技术你用特定的查询语句就能只加载你需要的对象。
在性能层面来讲,SQLite和Core Data是很相似的。他们的不同在于具体使用方法。Core Data代表一个对象的graph model,但SQLite就是一个DBMS。Apple在一般情况下建议使用Core Data,但是如果你有理由不使用它,那么就去使用更加底层的SQLite吧。
如果你使用SQLite,你可以用FMDB(https://GitHub.com/ccgus/fmdb)这个库来简化SQLite的操作,这样你就不用花很多经历了解SQLite的C API了。
23. 使用Autorelease Pool
`NSAutoreleasePool`负责释放block中的autoreleased objects。一般情况下它会自动被UIKit调用。但是有些状况下你也需要手动去创建它。
假如你创建很多临时对象,你会发现内存一直在减少直到这些对象被release的时候。这是因为只有当UIKit用光了autorelease pool的时候memory才会被释放。好消息是你可以在你自己的@autoreleasepool里创建临时的对象来避免这个行为:
NSArray*urls = <# An array of file URLs #>;
for(NSURL*url in urls) {
@autoreleasepool{
NSError*error;
NSString*fileContents = [NSString stringWithContentsOfURL:urlencoding:NSUTF8StringEncoding error:&error];
/*Process the string, creating and autoreleasing more objects. */
}
}
这段代码在每次遍历后释放所有autorelease对象
24. 选择是否缓存图片
常见的从bundle中加载图片的方式有两种,一个是用`imageNamed`,二是用`imageWithContentsOfFile`,第一种比较常见一点。
既然有两种类似的方法来实现相同的目的,那么他们之间的差别是什么呢?
`imageNamed`的优点是当加载时会缓存图片。`imageNamed`的文档中这么说:这个方法用一个指定的名字在系统缓存中查找并返回一个图片对象如果它存在的话。如果缓存中没有找到相应的图片,这个方法从指定的文档中加载然后缓存并返回这个对象。
相反的,`imageWithContentsOfFile`仅加载图片。
下面的代码说明了这两种方法的用法:
UIImage*img = [UIImage imageNamed:@"myImage"];// caching
//or
UIImage*img = [UIImage imageWithContentsOfFile:@"myImage"];// no caching
那么我们应该如何选择呢?
如果你要加载一个大图片而且是一次性使用,那么就没必要缓存这个图片,用`imageWithContentsOfFile`足矣,这样不会浪费内存来缓存它。
然而,在图片反复重用的情况下`imageNamed`是一个好得多的选择。
25. 避免日期格式转换
如果你要用`NSDateFormatter`来处理很多日期格式,应该小心以待。就像先前提到的,任何时候重用`NSDateFormatters`都是一个好的实践。
然而,如果你需要更多速度,那么直接用C是一个好的方案。Sam Soffes有一个不错的帖子(http://soff.es/how-to-drastically-improve-your-app-with-an-afternoon-and-instruments)里面有一些可以用来解析ISO-8601日期字符串的代码,简单重写一下就可以拿来用了。
嗯,直接用C来搞,看起来不错了,但是你相信吗,我们还有更好的方案!
如果你可以控制你所处理的日期格式,尽量选择Unix时间戳。你可以方便地从时间戳转换到NSDate:
-(NSDate*)dateFromUnixTimestamp:(NSTimeInterval)timestamp {
return[NSDatedateWithTimeIntervalSince1970:timestamp];
}
这样会比用C来解析日期字符串还快!需要注意的是,许多web API会以微秒的形式返回时间戳,因为这种格式在javascript中更方便使用。记住用`dateFromUnixTimestamp`之前除以1000就好了。
2.4.2 CPU性能调优
CPU跟踪模板为您提供的方法来确定你的应用程序如何使用多个核心,你使用多少能源和其他资源的测量。
寻找瓶颈与性能监视器计数器
性能监视器计数器(pmc)硬件寄存器,衡量事件发生在处理器。 他们可以用来帮助识别瓶颈在您的应用程序通过识别过度数量的一个特定类型的事件。 例如,大量的条件分支指令可能表明一段逻辑,如果重新安排,可能会降低所需数量的分支。 尽管PMC事件可以带来这些问题,这是由你来匹配您的代码和决定他们将帮助你提高你的应用程序的性能。
在工具中,您使用计数器仪器跟踪PMC事件。
跟踪PMC事件计数器乐器
1. 打开计数器跟踪模板。
2. 单击检查员按钮计数器的乐器。
3. 点击加号按钮(+)。
4. 单击事件改变到另一个事件。
PMC事件列表填充一组初始的常见的事件。 您可以添加特定于您的应用程序通过窗口菜单的事件。
添加新的PMC事件
1. 选择窗口>管理点事件。
2. 单击状态对应于所需的事件并选择可见或最喜欢的。
重要的是: PMC事件的数量,可以跟踪是依赖于硬件的。 试图跟踪太多的事件可能会导致一个错误。 试验设置来确定事件的数量,可以成功地跟踪一次。
如果你打算记录相同的PMC事件频繁,将它们保存在一个模板。 否则,他们将失去当你关闭文档。 保存跟踪信息模板,请参阅 拯救一个仪器跟踪模板 。
跟踪单个事件
事件分析器工具跟踪性能监视器中断(PMI)事件,但在这种情况下,只有一个事件跟踪,你可以得到更多的细节。 设置每个收集的样本集的大小事件分析器工具。 事件分析器然后为您提供信息如何积极跟踪PMI事件是在样例。 使用跟踪这些样品显示窗格中滑块识别大量的活动。 确定高活动区域后,用细节窗格中获得更多的信息在每个特定的例子。
添加新的PMI事件
1. 选择Window >管理点事件。
2. 单击状态对应于事件和选择可见或最喜欢的。
3. 阈值的字段中,输入一个事件的次数必须发生在一个示例。
选择你想要的PMI事件跟踪通过选择它从事件名称的弹出式菜单控制。 如果没有列出所需的事件,确保您拥有启用它。 看到 添加新的PMC事件 创建一个新的事件。图显示了事件分析器跟踪一个PMC事件。
图跟踪一个PMI事件与事件分析器工具
节能与能源诊断跟踪模板
能源诊断跟踪模板提供了关于能源使用的诊断,以及基本的开/关状态主要设备组件。 该模板由能源使用、CPU活动,网络活动,显示亮度,睡眠/唤醒,蓝牙,无线网络,和GPS仪器。
能源诊断日志记录,你的iOS设备记录与能源相关的数据不同时使用的设备。 因为日志记录是有效的,你可以记录所有的一天。 日志持续而iOS设备处于睡眠模式,但是如果设备电池干燥或iOS设备电源关闭,运行日志数据丢失。
开发人员设置的发展似乎只有在设备供应。 设置设备重启后消失。 Xcode恢复设置通过连接装置或仪器。
足够的能源使用事件记录后,您可以通过导入日志数据分析它们从电话到Xcode仪器能源诊断模板。 寻找高能源的使用领域,看看你是否在这些领域可以减少能源的使用。
跟踪能源使用iOS设备上
1. 打开开发人员登录iOS设备你想捕捉数据的地方。
2. 以用户角度去使用调试您的APP。
3. 获取数据后,关掉开发日志。
减少你的应用程序使用的能量通过确保你关掉Recode。 您可以验证如果你有关闭特定的无线电使用能源诊断跟踪模板。 每个广播与红色描述跟踪和黑色面板中指定,指定它是关闭的。
与多核跟踪检查线程的使用模板
多核跟踪模板分析多核性能,包括线程状态、调度队列,并阻止使用。 它是调度线程工具。
线程状态工具为您提供了一个图形表示的每个线程状态在特定时间运行。 每个块用不同颜色来帮助你识别每个线程。 经过多个线程状态改变很容易通过改变颜色的识别跟踪窗格。 图7显示了四个线程被跟踪。
图7线程活动显示的线程状态跟踪模板
查看应用程序的线程使用
1. 选择多核跟踪模板。
2. 运行您的应用程序。
3. 通过选择复选框选择线程来检查标记列在细节窗格中。
以下跟踪中捕获操作窗格。 颜色符号是默认颜色为每个行动,但他们可以改变你。
未知/终止(灰色)。 仪器无法确定线程的状态或被终止。
等待(黄色)。 线程正在等待另一个线程来执行一个特定的行动。
暂停(深蓝色)。 线程被放入挂起状态不会持续下去,直到它是专门告诉恢复运行。
要求暂停(浅蓝色)。 已经发送一个请求的线程将进入挂起状态。
运行(绿色)。 线程正在运行。
运行队列(黑色)。 队列中的线程运行。 之后,它会运行一个CPU。
等待不间断(不间断)(橙色)。 线程正在等待另一个线程来执行一个特定的行动和等待期间不能被打断。
空转处理器(白色)。 一个处理器线程是活动的,但不执行任何操作。
随着线程状态仪器,多核模板包含派遣仪器。 使用调度工具来查看当你执行调度队列。 你可以看到分派线程能持续多久和多少块。
多核跟踪模板显示在应用程序线程交互。然而,你不能够看到哪些核心被使用。 看到核心使用应用程序,请参阅 深入研究核心使用时间分析器跟踪模板 。
深入研究核心使用时间分析器跟踪模板
分析器跟踪模板执行低开销的时候,基于时间的采样系统的cpu上运行的进程。 它包含的时间分析器工具。
CPU策略的时间分析器工具显示了应用程序如何利用多核。 选择CPU战略跟踪文档中的配置跟踪窗格中显示的时间在x轴和y轴上的处理器核心。 CPU策略使用视图有助于比较核心的使用在给定的时间段。 有效的核心并发提高应用程序的性能。 重使用单个核心而其他领域核心保持安静可以描述区域需要更大的优化。
查看单个核心的使用
1. 打开时间分析器工具。
2. 选择你的应用从弹出菜单中选择目标。
3. 点击记录,锻炼你的应用程序,然后单击停止捕捉数据。
4. 单击CPU策略按钮。
5. 选择使用。
6. 寻找核心使用不平衡。
确保您的应用程序是使用多个核心同时通过跟踪窗格的放大。 很快一个或两个线程之间跳转的核心可以让它像时同时使用多个核心在现实中,只有一个核心是使用在任何时候。
软件性能测试理论手札(二)相关推荐
- nas 软件 性能测试,理论读写性能测试
评测平台介绍与说明:硬件平台 CPUIntel Core i7 4770K 主板华硕Z87-A 内存金士顿 DDR3-1600 4G*2 硬盘主盘:浦科特M5P 512G 测试盘:HGST 4TB N ...
- 软件性能测试平台,评测平台介绍及理论性能测试
评测平台介绍与说明:硬件平台 CPUIntel Core i7 4770K 主板华硕Z87-A 内存金士顿HyperX FURY DDR3-1600 8Gx2 硬盘系统盘:浦科特M5P 512G 测试 ...
- 性能测试 理论初探(七) 性能测试工具 介绍 目前知道哪些性能工具?分别用在什么软件或平台的性能测试?服务端、web前端、移动端等 性能测试工具有哪些?
文章目录 一.前言 二.常见性能测试工具 1.服务端性能测试工具 1.1 Jmeter 1.2 Locust 1.3 LoadRunner 1.4 LoadNinja 1.5 Jmeter + Pro ...
- 《精通软件性能测试与LoadRunner最佳实战》—第1章1.1节软件测试基础
本节书摘来自异步社区<精通软件性能测试与LoadRunner最佳实战>一书中的第1章1.1节软件测试基础,作者于涌 , 王磊 , 曹向志 , 高楼 , 于跃,更多章节内容可以访问云栖社区& ...
- 《软件性能测试、分析与调优实践之路》学习
这是一本理论和实践相结合的同时面向研发和测试岗的关于性能分析诊断调优实践的图书,比起其他的很多性能测试的图书,本书中内容更侧重于介绍如何去发现性能问题.分析诊断性能问题以及对发现的性能问题进行调优.书 ...
- 浅谈软件性能测试中关键指标的监控与分析(转)
浅谈软件性能测试中关键指标的监控与分析 一.软件性能测试需要监控哪些关键指标? 软件性能测试的目的主要有以下三点: Ø 评价系统当前性能,判断系统是否满足预期的性能需求. Ø 寻找软件系统可能存在 ...
- 游戏软件性能测试怎么做?常规测试知识要点总结
随着网络游戏市场的进一步繁荣,人们对游戏软件关注度和性能要求越来越高.就拿几款热门手游来说,如果游戏使用人群基数大,那么势必会对游戏软件服务器产生压力,玩家的体验也不好.所以做好游戏软件性能测试对于开 ...
- 08-01 Jmeter 核心原理与性能测试理论
Jmeter 核心原理 基于协议,模拟真实用户场景,并通过多线程模拟用户发起请求. 基于协议:性能测试的对象是网络分布式架构的软件,而网络分布式架构的核心是网络协议 多线程:人的大脑是单线程的,电脑的 ...
- 软件性能测试方案怎么编写?权威的性能测试报告如何申请?
软件性能测试是通过自动化的测试工具模拟多种正常.峰值以及异常负载条件来对系统的各项性能指标进行测试.性能测试在软件的质量保证中起着重要的作用,它包括的测试内容丰富多样.负载测试和压力测试都属于性能测试 ...
最新文章
- java combinationsum_Leecode39 combination-sum
- SAP Spartacus User form通过label标签的实现原理
- java程序 构建mycircle类_Java语言程序设计(十九)对象和类的应用实例
- 何传启:第六次科技革命的三大“猜想
- 拓端tecdat|r语言多均线股票价格量化策略回测
- CIE1931标准色度系统
- 交互设计好书推荐:【A029】[图灵交互设计丛书].简约至上:交互式设计四策略.第2版
- 计算广告——读书笔记(一)
- [教你做小游戏] 《五子棋》怎么判断输赢?你能5分钟交出代码吗?
- python excel数据处理?
- 能链科技子公司上海能链获颁高新技术企业资质
- Python3网络爬虫(四):使用User Agent和代理IP隐藏身份
- 通信专业应掌握的计算机软件,全国通信专业技术人员职业水平(中级)考试大纲...
- python波形峰值检测
- 按 特定区域/指定位置 批量裁剪图片
- 【网络工程师】<软考中级>网络安全与应用
- 如何评估流程管理的紧迫度
- Goole Chrome 谷歌浏览器无法打开设置、闪退、崩溃
- (二)关于S4HC用户登陆S系统说明
- 零基础小白入门建模行业,学习3dmax的几点建议!快来学习