性能优化之卡顿分析

Android 每隔16ms发出一个VSYNC信号,触发CPU跟GPU进行界面渲染,计算跟绘制,让界面的帧率在1秒内达到60fps,使视觉效果达到自然流畅。如果一个在16ms内不能完成界面的渲染,计算跟绘制,就会产生丢帧的现象,丢帧就会造成应用卡顿现象。

一、引起应用卡顿的原因

1.过度绘制。过度绘制就是在同一帧情况下对同一块像素区域进行重复绘制。这样会加重GPU跟CPU的渲染压力,导致渲染时间过长。
2.布局嵌套过多。布局嵌套过多过于复杂也会导致CPU跟GPU的渲染,计算,绘制压力。
3.动画执行次数过多。
4.执行耗时操作。文件读写,数据操作,较大数据初始化等较为耗时的操作阻塞线程。
5.频繁GC。执行GC的时候,所有操作都需要暂停,等到GC结束后,才能继续执行操作。这样就可能会阻塞CPU跟GPU的渲染,计算跟绘制。

二、卡顿的分析步骤思路

分析卡顿主要使用可以检测UI卡顿的工具来分析,知道了可能引起卡顿的原因后,就可以针对每一点使用相应的工具来检测分析。我们按顺序从第一点开始。

1、查看过度绘制情况—调试GPU过度绘制

打开手机的“调试GPU过度绘制”功能分析UI的绘制情况
在手机的设置->开发选项->调试GPU过度绘制 打开调试功能。打开后就可以看到UI的绘制情况了。
可以使用此功能初步查看UI的绘制情况,然后进行相应的优化。
这里写图片描述
蓝色,淡绿,淡红,深红代表了4种不同程度的绘制情况,其中蓝色表示只绘制一次,最为理想,深红表示绘制4次以上,性能最差,最为忌讳。对红色以上部分进行重点优化:

  • 减少背景重叠,尽量在子View设置背景,不要在根View设置背景,防止子View有了背景,根View也有了背景,造成重叠。
  • 减少布局的嵌套,减少布局层级。
  • 去除Activity的默认背景色。
  • 在自定义View的onDraw或者自定义ViewGroup的drawChild方法中使用Canvas的clipRect()方法绘制指定区域。

2、查看布局嵌套情况—HierarchyViewer

在Android studio的导航栏的Tools->Android->Android Devices Monitor, 选择Window -> Hierarchy View。
这里写图片描述
使用HierarchyViewer 可以查看UI的布局层级,可以看到布局层级是否过深,是否可以再进一步优化。

3、查看执行耗时情况—systrace + traceview

Systrace 查看UI绘制的帧率情

Systrace 可以用来分析由于丢失帧而导致的UI卡顿问题。当出现丢帧时,会以 Alert 提示并给出优化的提示。
Systrace会自动分析信息,将性能问题直接以alerts的方式高亮显示。

1、生成 trace 文件
启动Systrace:Android Studio,Tools–android–Android Device Monitor,再点击DDMS的Systrace图标。
这里写图片描述
启动之后,生成trace.html 文件,在Chorme浏览器中打开进行分析:
这里写图片描述
2、分析问题
F圆圈表示一帧(Frame),有绿,黄,红三种状态,渲染时间依次递增。
正常绘制是1秒60帧,大约一帧16.6毫秒,在这个值以下是正常颜色绿色,如果超过它就会变成红色、黄色。一般红色就是有问题的,要优化的地方。。单点击后可查看Frame详细信息,根据Alert提示解决问题。
点击某个单独的 Frame,按下m键可以看到该 Frame 的执行时间。并且通过alerts提示该展现问题,以及建议如何处理。
这里写图片描述
在左下角我们可以看到 “Scheduling delay”这条Alert提示里。
Scheduling delay(调度延迟)的意思就是一个线程在处理一块运算的时候,在很长一段时间都没有被分配到CPU上面做运算,从而导致这个线程在很长一段时间都没有完成工作。
2、代码控制开始和结束
以上方式不能在代码中控制Trace运行的开始和结束,那有没有办法呢?答案是肯定的。
Android定义了一个Trace类,这个 Trace 类就是用来做数据采集的。我们可以用这个类来自定义Trace Label ,解决在代码中控制开始和结束。可以在代码中插入如下代码来分析某个特定的过程:

//生成的trace文件中,会在跟踪的代码段执行对应时间轴区间打上一个tag标记
Trace.beginSection("Trace begin");  
...
//Trace的begin与end必须在同一线程之中执行
Trace.endSection(); 
Traceview分析函数执行时间

使用systrace分析之后,并不能定位到具体的代码,这时就可以使用 Traceview 来定位具体的代码了。
Traceview可以清晰地看到每个方法的执行耗时和调用次数,然后定位具体的卡顿代码。

1、生成 trace 文件

  • 使用代码
  • 使用DDMS

1.1 使用代码生成 trace 文件

Debug.startMethodTracing(String tracePath);
//...
Debug.stopMethodTracing();

1.2 使用DDMS生成 trace 文件
在Android studio的导航栏的Tools->Android->Android Devices Monitor选择DDMS,然后点击Start Method Profiling,即可开始:
这里写图片描述
然后操作我们需要检测的界面,过一会之后,再点击这个按钮,即可停止。DDMS就会自动打开如下界面:
这里写图片描述

Name:名称
Incl Cpu Time :方法及其调用方法总共占用CPU的时间。
Excl Cpu Time :方法本身占用CPU的时间。
Incl Real Time :方法及其调用方法真实执行时间。
Excl Real Time :方法本身真实执行时间。
Calls+Recur Calls/Total:方法被调用次数以及递归调用次数占总调用次数的百分比
Cpu Time/Calls:方法执行的平均占用CPU时间。
Real Time/Calls:方法执行的平均真实执行时间。

2、定位问题
使用Traceview,一般可以定位两类函数:

  • 执行时间比较长。
    点击 TraceView 中的 Incl Real Tim,按照方法执行时间从高到低排序
  • 执行时间断,但是调用次数过于频繁的。
    点击 TraceView 中的 Calls + Recur Calls/Total ,按照调用次数从高到底排序

我们可以对相关属性进行排序,加上 Find 搜索,从而定位执行时间较长的或者调用过于频繁的函数并进行优化。

4、查看GC情况—Memory Monitor

由于GC导致UI卡顿,这种情况一般可能是由于内存抖动,频繁GC造成的。
可以使用 Allocation Tracker 来查看是否有内存抖动情况, Allocation Tracker可以查看代码中分配的对象类型、大小情况。

在 Android studio 中的 Android Monitor -> Memory Monitor 可以查看应用的内存使用情况,以及实时的GC情况。
点击 Memory Monitor -> Start Allocation Tracker 按钮开启追踪内存情况:
这里写图片描述
等程序运行几秒后,再按一下结束追踪,会打开如下分析界面:
这里写图片描述

三、性能监控组件 Blockcanary

Blockcanary 是检测UI卡顿利器

猜你喜欢

转载自blog.csdn.net/iluojie/article/details/80631775