Android应用性能优化之分析工具
上一次记录了解决过度绘制的过程,这一次,想先弄清个概念性的东西,就是如何判断顺不顺畅?
这东西其实最初我自己也觉得有点废话,用起来会卡就明显是不顺畅咯。
但这东西就跟我很想吐槽很多应用一样,明明那么卡还放出来一样的道理。
理论永远是理论,实践才是第一生产力。
因为我自己的应用也能感觉到卡顿,现在回头分析,能明白,卡顿永远不是“用心的程序员”原本的初衷,但很多东西,真心是难言之隐。
知错就改才是好人...所以要改,就要知道究竟错在哪。
1、纵观全局
对于顺畅度的分析,首先要知道一个整体情况,是局部,还是全局,这样在优化上才能有方向。
如果是局部问题,那就需要仔细分析出具体的相关操作,如果是大体上的问题,那在思考的时候,就需要从整体的实现机制来考虑,有可能是实现方式上出现了问题。
在android4.1中,谷歌提供了一个工具来,叫做“ GPU呈现模式分析(Profile GPU rendering)”,在开启这个功能后,系统就会记录保留每个界面最后128帧图像绘制的相关时间信息。
如果是在开启应用后才开启此功能,记得先把应用结束后重新启动。
开启后操作你需要分析的部分(比如滑动列表之类的),然后执行adb命令
$ adb shell dumpsys gfxinfo com.xxxx.xxx
在执行的结果中,有一块叫做“Profile data in ms”底下有一堆数据.
Draw:表示在Java中创建显示列表部分中,OnDraw()方法占用的时间。
Process:表示渲染引擎执行显示列表所花的时间,view越多,时间就越长
Execute:表示把一帧数据发送到屏幕上排版显示实际花费的时间。其实是实际显示帧数据的后台缓存区与前台缓冲区交换后并将前台缓冲区的内容显示到屏幕上的时间。所以这个时间,一般都很短。
PS:View类包含Surface(变量名mSurface),每个Surface通常对应两个buffer,一个front buffer, 一个back buffer。(4.1之后是3个,一个前,两个后)其中,back buffer就是canvas绘图时对应的bitmap (研究Android_view_Surface.cpp::lockCanvas)。因此,绘画总是在back buffer上,需要更新时,则将back buffer和front buffer互换。
Draw + Process + Execute = 完整显示一帧 ,这个时间要小于16ms才能保存每秒60帧。
将数据复制到excel中(win记得逐列复制,mac下就直接复制过去吧),然后将数据生成“堆积柱形图”
从图上看,能看出几个现象。第一,确实4.1的黄油项目还真的有点作用,每帧的时间控制在16ms左右。第二,有几帧超过16ms,确实会有丢帧的现象。
看来,页面的卡顿应该是个别操作的问题。
但这种数据是否还能看出其他问题呢?
按照3个数据分别标示的内容,理论来讲,如果UI线程占用的时间过长,Draw的时间数据会应该会很长,所以做了个实验,在UI线程中睡了1S。得到了下面这个图。
从图上看有几帧Draw部分异常的高就能看出,Draw部分能看出UI线程的大体使用情况。
当然,其实这个数据主要能看出的是整体情况,单独的某个部分跟测试的环境也有很大关系,比如一下2组数据,都是instagram的,同样的数据,上面是Desire Z 4.1系统,下面是盖3 4.1系统,在Execute部分,两者有明显的差距。
2、具体分析
“GPU呈现模式分析”的数据只能说明个现象,比如上面提到的数据,能说明在实际运行中会有短暂的长时间绘制问题。但造成问题的具体原因并没有说明。
而且“GPU呈现模式分析”显示的是最后128帧的数据,但丢帧也有可能是两帧之间存在长时间的操作而造成的。
所以我们需要分析帧与帧之间的情况,才能对所分析应用的整体性能情况有个更升入的了解。
在android中提供了两个工具来达到这个目的:1、Systrace (这工具坑的我....等下再吐槽) 2、traceview
Systrace是对整个系统进行分析,数据比较准确,当然也包括我们所要分析的应用。
当这个工具的使用是有条件限制的:
(1)是4.1之后才提供的工具。
(2)手机的内核一定要支持trace(可以查看是否存在/sys/kernel/debug/tracing 这个目录),所以很多第三方ROM或者三星之类的rom都在内核中remove了这个模块。模拟器里面好像也都没有。[这个坑的我刷了无数多的rom才找到适合的...之前的one x我记得好像也有,这个也间接说明一点,作为开发者,还是乖乖的买亲儿子好]
Systrace的运行方式有两种,一种是运行sdk包下的py文件,这种要求的环境配置比较多。另一种就是在adt下的工具,点击直接运行。所以下面的使用介绍主要是这种。
在流畅程度的这种特殊分析情景下,我们一般只关注图形性能。所以我们要选择Graphics和View.还有其他很多选项,如果是在做音频处理或者视频播放的分析测试话,可以选择其他选项。
确认运行之后,滚轮我们要测试的列表,工具会记录5秒钟的数据,之后我们回得到一个html页面。打开后,我们能看到页面中显示了系统中一切运行情况的概述。
浏览的操作时通过WASD来完成,W/S 放大/缩小 A/D 左移/右移
页面中有个surfaceFlinger,知道android绘制原理的人应该能明白,这个就是负责绘制Android应用程序UI的服务,所以surfaceFlinger能反应出整体绘制情况,一般正常情况都是连续的,如果出现空档,一种是没有操作或者滑动到头,没东西需要绘制,这种属于正常,另一种就是有问题存在,有其他操作时间过长。
对应所要分析的程序那行,放大后就能看到具体的情况,点击后能看到每个部分所使用的时间。
比如
deliverInputEvent是系统提供的触摸事件。
performTraversals是开始布局并且绘画显示画面的过程。
draw是绘画的过程。
...
对于一个listview,如果deliverInputEvent过长,很有可能是在adapter中的getView方法中处理时间过长导致。
所以通过Systrace的数据,可以大体上的发现是否存在性能问题。
但如果要知道具体情况,就需要用到另外一个工具。
traceview
这个工具其实比较简单,是一个分析器,记录了应用程序中每个函数的的执行时间。在DDMS中,选中要分析的进场,点击“Start method profiling”(就是右上角有个红点的图标)。然后开始操作要分析的应用,然后再次点击按钮来停止跟踪。
然后下面显示的数据应该挺通俗易懂的。
具体的可以参见:http://hubingforever.blog.163.com/blog/static/17104057920112825035143/
这里我想介绍下我使用的一个经验。
ViewRootImpl.draw(),这个是绘制函数,点击后,绘制的部分就会被突出出来。从理论上讲,只要操作时没有太多停顿,draw()的图示应该是较为连续的。并且要保持顺畅,每一个draw区域应该在16ms及以下。
所以一旦看到区域有大于16ms的,就可以认真分析下,看看都做了些什么操作。从而找到导致绘制时间过长的问题所在。
对于这些工具的使用,虽然很大程度上能够帮助我们更快的定位到问题之处,但还是有许多局限的地方。
如果对android整体系统原理有一定的理解,并且深刻知道自己的程序的运转情况,这样分析起来,才会炉火纯青。
以上是我个人的一些看法,希望能帮助到大家,没写的太细,够用就好,因为有些部分,自己也有很多疑问,找到了一堆资料,发现也没有说明的特别详细的地方。
以下是参考的一些地方,大家可以去看看,有些需要走出去(怎么出去这东西每个程序员都会吧?):
http://www.youtube.com/watch?v=Q8m9sHdyXnE(google IO的,需翻)
http://blog.chengyunfeng.com/?p=458(这个是上面的中文翻译)