让我们一起爱米兰
站内搜搜:
移动设备
请扫描二维码
或访问
m.milan100.com
您所在的位置 -> 米兰百分百 -> android相关 -> Android应用性能工作Systrace

Android应用性能工作Systrace

点击数:9323 发表时间:2015-11-08 11:15:17 作者: 来源链接:
分享到:
分享到微信

Systrace

Systrace是一个非常好但却有可能被你忽视的工具,这是因为开发者们往往不确定Systrace能够为他们提供什么样的信息。

Systrace会展示一个运行在手机上程序状况的概览。这个工具提醒了我们手机其实是一个可以在同一时间完成很多工作的电脑。在最近的一次SDK更新中,这个工具在数据分析能力上得到了提升,用以帮助我们寻找性能问题之所在。

下面让我们来看看Systrace长什么样子:


你可以通过Android Device Monitor Tool或命令行来生成Systrace文件,想了解更多猛戳此处

在视频中,我向大家介绍了Systrace中不同区域的功能。当然最有趣的还是Alerts和Frames两栏,它们展示了通过手机来的数据而生成出来的可视化分析结果。让我们来选择最上方的alerts瞧瞧:


这个警告指出了,有一个View#draw()方法执行了比较长的时间。我们可以在下面看到问题的描述,链接,甚至是相关的视频。下面我们看Frames这一行,可以看到这里展示了被绘制出来的每一帧,并且用绿、黄、红三颜色来区分它们在绘制时的性能。我们选一个红色帧来瞅瞅:


在最下方,我们看到了与这一帧所相关的一些警告。在这三个警告中,有一个是我们上面所提到的(View#draw())。接下来我们在这一帧处放大并在下方展开“Inflation during ListView recycling”这条警告:


我们可以看到警告部分的总耗时,32毫秒,远高于了我们对保障60fps所需的16毫秒绘制时间。同时还有更多的ListView每个条目的绘制时间,大约是6毫秒每个条目,总共五个。而Description描述项中的内容会帮助我们理解问题,甚至提供问题的解决方案。回到我们上一张图片,我们可以在“inflate”这一个块区处放大,并且观察到底是哪些View在被填充过程中耗时比较严重。

下面是另外一个渲染过慢的实例:


在选择了某一帧之后,我们可以按“m”键来高亮这一帧,并且在上方看到了这一部分的耗时,如图,我们看到了这一阵的绘制总共耗时超过19毫秒。而当我们展开这一帧唯一的一个警告时,我们发现了“Scheduling delay”这条错误。

Scheduling delay(调度延迟)的意思就是一个线程在处理一块运算的时候,在很长一段时间都没有被分配到CPU上面做运算,从而导致这个线程在很长一段时间都没有完成工作。我们选择这一帧中最长的一块,从而得到更加详细的信息:


在红框区域内,我们看到了“Wall duration”,他代表着这一区块的开始到结束的耗时。之所以叫作“Wall duration”,是因为他就像是墙上的一个时钟,从线程的一开始就为你计时。

但是,CPU Duration一项中显示了实际CPU在处理这一区块所消耗的时间。

很显然,两个时间的差距还是非常大的。整个区块耗时18毫秒,而在这之中CPU只消耗了4毫秒的时间去运算。这就有点奇怪了,所以我们应该看一下在这整个过程之中,CPU去干吗了。


可以看到,所有四个线程都非常的繁忙。

选择其中的一个线程会告诉我们是哪个程序在占用他,在这里是一个包名为com.udinic.keepbusyapp的程序。在这里,由于另外一个程序占用CPU,导致了我们的程序未能获得足够的CPU资源。

但是这种情况其实是暂时的,因为被其他后台应用占用CPU的情况并不多见(- -),但仍有其他应用的线程或是主线程占用CPU。而Traceview也只能为我们提供一个概览,他的深度是有限的。所以要找到我们app中到底是什么让我们的CPU繁忙,我们还要借助另一个工具——Traceview。

Traceview

Traceview是一个性能测试工具,展示了所有方法的运行时间。下面让我们来瞅瞅它是啥样的:


这个工具可以从Android Device Monitor中打开也可以通过代码打开。更多的消息信息请看这里

下面让我们来看看每一列的含义:

  • Name——方法名,以及他们在上面图表中所对应的颜色。

  • Inclusive CPU Time——CPU在处理这个方法以及所有子方法(如被他调用的所有方法)的总耗时。

  • Exclusive CPU Time——CPU在处理这一个单独方法的总耗时。

  • Inclusive/Exlusive Real Time——从方法的开始执行到执行结束的总耗时,和Systrace中的“Wall duration”类似。

  • Calls+Recursion——这个方法被调用的次数,以及被递归调用的次数。

  • CPU/Real time per Call——在处理这个方法时的CPU耗时的平均值以及实际耗时的平均值。另外的列展示了这个方法所有调用的累计耗时。

我打开一个滑动不太顺滑的应用。开启记录,滑动一点后停止记录。展开getView()方法,如下图:


这个方法被调用了12次,每次CPU会消耗3毫秒左右,但是每次调用的总耗时却高达162毫秒!绝对有问题啊!

而看看这个方法的children,我们可以看到这其中的每个方法在耗时方面是如何分布的。Thread.join()方法战局了98%的inclusive real time。这个方法在等待另一个线程结束的时候被调用。在Children中另外一个方法就是Tread.start()方法,而之所以整个方法耗时很长,我猜测是因为在getView()方法中启动了线程并且在等待它的结束。

但是这个线程在哪儿?

我们在getView()方法中并不能看到这个线程做了什么,因为这段逻辑不在getView()方法之中。于是我找到了Thread.run()方法,就是在线程被创建出来时候所运行的方法。而跟随这个方法一路向下,我找到了问题的元凶。


我发现了BgService.doWork()方法的每次调用花费了将近14毫秒,并且有四十个这东西!而且getView()中还有可能调用多次这个方法,这就解释了为什么getView()方法执行时间如此之长。这个方法让CPU长时间的保持在了繁忙状态。而看看Exclusive CPU time,我们可以看到他占据了80%的CPU时间!此外,根据Exclusive CPU time排序,可以帮我们更好的定位那些耗时很长的方法,而他们很有可能就是造成性能问题的罪魁祸首。

关注这些耗时方法,例如getView(),View#onDraw()等方法,可以很好的帮助我们寻找为什么应用运行缓慢的原因。但有些时候,还会有一些其他的东西来占用宝贵的CPU资源,而这些资源如果被运用在UI的绘制上,也许我们的应用会更加流畅。Garbage Collector垃圾回收机制会不时的运行,回收那些没用的对象,通常来讲这不会影响我们在前台运行的程序。但如果GC被运行的过于频繁,他同样可以影响我们应用的执行效率。而我们该如何知道回收的是否过于频繁了呢…

5
很 好
0
一 般
0
差 劲
热门新闻
相关文章
上一篇: 13项诀窍助你的Android应用顺利入驻Google Play商店
下一篇: adb工具的使用
评论区
匿名

返回首页 | 收藏本页 | 回到顶部
Copyright 2010. 米兰百分百 Powered By Bridge.
京ICP备15050557号