近期读到《Speed up your app》一文。这是一篇关于Android APP性能分析、优化的文章。在这篇文章中,作者介绍他的APP分析优化规则、使用的工具和方法。我觉得值得大家借鉴。英文好的读者可读原文(链接:http://blog.udinic.com/2015/09/15/speed-up-your-app)。

1、作者的规则

作者每次着手处理或寻找性能问题时,遵循下列规则:

  • 时常检测

在更新APP前后,用测试工具软件多检测几次APP性能,可快速得到测试数据。这些数字是不会说谎的。而仅仅用眼睛观察APP性能是肯定不行的。如你在观察几次相同的动画效果后,你就想象它运行的够快了,从而忽略一下问题。

  • 使用低端设备

如今硬件性能在不断的提升,如果仅在最新设备运行APP,可能不能充分暴露出APP中存在的性能问题。另外,尽管用户设备换手率已经很高了,但仍然不是所有用户都是使用最新的和最强功能的设备。所以应该使用低端设备上,运行APP,这可以帮助你更有效地发现问题。

  • 权衡

性能优化是要综合各方面因素进行评判、权衡。因为优化一项性能可能是要以牺牲另一项性能为代价的。分析、查找、修复是要花费很多时间。你要准备好自我牺牲。

2、作者的分析方法及使用工具

作者采用自顶向下方法,从手机运行的概况开始,逐级深入分析:方法的性能、内存使用情况、GPU渲染效果、视图层次、图形叠加绘制、图像透明值;解释Honeycomb引入的硬件加速以及视图层。

2.1 Systrace

手机实际就是一台功能强大的计算机,同时间做很多事情。Systrace能够展示手机运行的概况。

作者在Systrace中选取一个Alert,做为例子,讲解分析发现问题的方法:

1)由Alert找到函数(如:long View#draw()),再展开“Inflation during ListView recycling”

2)可以查看到函数的耗时,更详细观察分析其中哪项花费时间较长。

3)选择一帧查看它花费多久时间。如有一帧绘制用时超过19ms。展开“Scheduling delay”

4)它的值(Wall duration和CPU duration之间的差异)表明有很长时间CPU没有安排这个线程。

这就需要查查在整个这段时间里CPU都做了什么?但是Systrace只能查看运行概况,还不能得到更深层次的分析。为了找到CPU运行繁忙的真正原因,作者使用另一个工具:Traceview。

2.2 Traceview

Traceview是性能分析工具,可以显示每个方法运行时间。可从Android Device Monitor中启动,也可从代码中启动。

作者以“滚屏”动作为例说明Traceview分析方法。在“滚屏”动作的跟踪记录中,找到getView()方法,发现它被调用12次,每次CPU用时约3ms。但是每次完成整个调用却用时162ms!这就是个问题!

作者就继续查看getView()的子方法,查看各个子方法所用时间在总时间中比例。他发现Thread.join()的Inclusive Real Time占用约98%。他顺藤摸瓜,找启动子方法的Thread.run()方法(它是创建一个新线程时所调用的方法),逐个跟着,直到找到“元凶”:BgService.doWork()方法。

另外,GC(Garbage Collector – 垃圾收集器)不定期运行清理不用的对象。GC的频繁运行也会使得APP运行慢下来。为此,作者的下一步就是针对内存进行分析。

2.3 内存分析(Memory Profiling)

Android Studio逐步在改善,有越来越多的工具可以帮助我们找到和分析性能问题。作者用其分析内存使用情况。

2.3.1 Heap dump

Heap Dump可以看到Heap中依据类名排序实例的直方图。每个都有分配对象的总数,实例的大小和留在内存中对象的大小。后者告诉我们这些实例释放后,能够释放多少内存。这可帮助我们识别出大的数据结构和对象关系。这些信息可以帮助我们构建更有效的数据结构,解开对象之间联系以减少内存驻留,最终尽可能的减少内存占用。

在分析中,可发现“内存泄漏”。解决方法就是要记得在活动即将被销毁时调用onDestory()方法删除引用。

内存泄漏和较大对象的heap空间占用,使得有效内存减少,频繁引发GC事件,试图释放更多的heap空间。这些GC事件占用CPU,降低了APP性能。如果有效的内存数量不足与满足APP,且heap空间不能在扩大,就引发 —— OutOfMemortException —— APP崩溃。

Eclipse MAT(Eclipse Memory Analyze Tool)也是不错的内存分析工具。

2.3.2 Allocation Tracker

Allocation Tracker可生成在跟踪期间内存分配给所有实例的情况报告,报告可按类分组或按方法分组。它以很好的可视化方式展示哪个实例所获得内存最多。

使用这些信息,可以找出分配大内存的方法,和可能频繁触发GC的事件。

2.3.3 General memory tips

作者给出一些技巧:

  • 枚举

一直是讨论性能的热门话题。枚举比普通常数占用更多的内存空间吗?是的。但这肯定是坏事吗?未必。如在编写代码库,需要强类型安全性,这就应该使用它。如果有一组可以归结在一起的常数,此时使用枚举也许不不合适。怎样决定,你需要权衡考虑。

  • Auto-boxing

是自动将原始数据类型转换为其对应的对象表示(如:int 到 Integer)。每次原始数据类型被“装箱”到对象,就会产生一个新的对象(我知道这令人震惊)。如果有许多这样的操作,那么GC就频繁地运行。由于将原始类型数据赋值到对象时,自动进行auto-boxing的,就很容易忽视它的数量。解决方案就是尽量使数据类型保持一致。如果要在整个APP中使用原始数据类型,就尽量避免在没有实际需要时进行Auto-boxing。使用内存分析工具可以找到许多对象是表示原始数据类型。也可以用Traceview寻找到Integer.valueOf(),Long.valueOf()等等。

  • HashMap与ArrayMap / Sparse*Array

在Auto-boxing相关问题中,使用HashMap时,就要求用对象作为键值。如果在APP中用原始int类型,那么在使用HashMap时就需要将int转化到Integer。这种情况也许就需要用SparesIntArray。如果在键值仍然需要对象类型的情况下,也可以改用ArrayMap类。它非常类似HashMap,只是在其内部工作方式不同,是以降低速度为代价,使用较少的内存。这两者占用内存都比HashMap小,但检索所花费的时间略高于HashMap。如果数据项少于1000,它们的运行时没有什么差别。

  • Context Awareness

Activity内存比较容易泄漏。由于它们保持UI的所有视图层次,占用大量的空间,所以它们的泄漏也是非常“昂贵的”。许多操作都要求Context对象,你发起Activity。假如引用被缓存,并且该对象的存活期要长于你的Activity,如果没有清理它的引用,你就产生了内存泄漏。

  • 避免非静态内部类(inner class)

创建一个非静态内部类,并实例化它,就创建对外部类的隐式引用。如果内部类实例需要的时间比外部类长,这外部类就要在内存中保留,即使它不再需要了。例如,在Activity类内部,创建一个扩展AsyncTask的非静态类,然后着手启动异步任务,在它运行时,销毁活动。该异步任务在其运行期间,都保持这一Activity运行。解决方案就是不要这样做。如果需要这样,就声明一个静态内部类。

2.4 GPU Profiling

Android Studio 1.4增加一项新功能:分析GPU渲染功能。作者详细讲解这一新功能的分析方法。

在GPU选项卡下,可以在屏幕上看到图形化显示的渲染每帧所花费的时间。图形中每条都表示被渲染的一帧。颜色表示进程的不同周期:

  • 绘画(蓝色)

表示View#onDraw()方法。那部分建立/更改DisplayList对象,然后转换成GPU能够理解的OpenGL命令。高的条形可能是视图复杂,而要求更多的时间绘制它们的显示列表,而许多视图在短时间内就失效了。

  • 准备(紫色)

在Lollipop中,加入另一个线程,以帮助UI线程渲染更快。这个线程叫:RenderThread。它的责任是转换显示列表为OpenGL命令,再发送给GPU。这样在渲染过程中,UI线程可以开始处理下一个帧。这时UI线程将所有资源传送给RenderThread。如果有许多资源要传递(如许多/繁重显示列表),这一步可能需要较长时间。

  • 处理(红色)

执行显示列表产生OpenGL命令。由于需要视图重绘,如果有许多/复杂显示列表要执行转换,这一步可能需要较长时间。当视图无效或是移动时,都要要重绘视图。

  • 执行(黄色)

发送OpenGL命令到GPU。由于CPU发送这些缓存的命令到GPU,并期待收回干净缓存,这就阻塞调用了。缓存数量有限,并且GPU也很忙 —— CPU会发现自己必须先等待缓存释放。因此,如果在这一步我们见高的条形,就可能意味着GPU在绘制UI时非常忙,这个绘制在短时间内太复杂了。

具体操作实例见原文。

2.5 Hierarchy Viewer

作者喜爱这个工具。他对许多开发者根本不使用这工具感到失望。

使用Hierarchy Viewer,可以完整地观察到屏幕视图层次和所有视图的属性。还可以导出主题(theme)数据,查看到每个样式的所有属性。但是,这只是在Hierarchy Viewer独立运行时,才能查看这些数据。而不可以从Android监控器中查看。

作者在设计布局和优化布局时使用这个工具。

作者认为有时间,可以对每张视图都测量以及它的所有子视图。颜色表示视图与树中其他视图的比较情况,很容易找出最薄弱的环节。由于我们可以预览视图,这样就可通过视图树,跟踪找出可删除的冗余步骤。这其中,对性能影响最大的,被称为Overdraw。

2.6 Overdraw

如果GPU需要在屏幕上绘制很多内容,绘制每帧都需要增加时间,这样执行周期就拉长了,在图形中以黄色表示。在一些图形上再叠加绘制,如在红色背景上绘制黄色按钮,这就发生Overdraw。这种情况下,GPU需要先绘制红色背景,再在其上绘制黄色按钮,Overdraw就不可避免了。如果有太多的Overdraw层,这就使得GPU超负荷运行,偏离16ms的目标。

设置“Debug GPU Overdraw”开发者选项,所有Overdraw的严重程度都以颜色表示出来。1~2倍的Overdraw算好的,甚至有些小的红色区也不坏。但是如果在屏幕上有许多红色,这就有问题了。但是都被红色覆盖。这就是问题了。作者建议这时仅用一种颜色设置背景来解决这个问题。

注意:默认主题声明一个全屏窗口背景颜色。如果有不透明布局的Activity覆盖在整个屏幕上,可以通过删除窗口的背景色消除这层Overdraw。

Hierarchy Viewer能够输出所有层次到PSD文件中,用Photoshop中打开。在Photoshop中研究不同的层就可展示布局中的所有Overdraw。删除冗余的Overdraw,努力性能提高到蓝色上。

2.7 Alpha

使用透明效果也会影响性能。为什么?

ImageView相互重叠。用setAlpha()设置alpha值,这将传递给所有的子视图,对帧缓冲区进行绘制。结果都重叠混在一起。幸好,OS有这个问题的解决方案。布局数据被复制到off-screen缓冲区,用alpha值对off-screen缓冲区进行处理后,再复制到帧缓冲区中。效果就好了些。但是,我们为此付出了代价:把“帧”缓冲区改为off-screen缓冲区,实际上增加了一个隐含的Overdraw层。OS就不知道处理了,所以默认情况下经常要进行复杂地操作。

不过还是有方法设置alpha值,避免off-screen缓冲区增加的复杂性:

  • TextView

用setTextColor()替代setAlpha()。使用文本颜色的alpha通道,就可直接用它来绘制的文本。

  • ImageView

用setImageAlpha()替代setAlpha()。理由同TextView。

  • Custom View

如果自定义视图不支持覆盖视图,这复杂行为是无关紧要的。可通过重写hasOverlappingRendering()方法,让其返回false,通知OS直接绘制自定义的视图。还可以通过重写onSetAlpha()方面,让其返回true,选择手动处理设置,各alpha值对应的操作。

2.8 Hardware Acceleration

在Honeycomb(蜂巢,Android 3.x)引入硬件加速后,在屏幕上渲染APP可以以新的绘制模型(http://developer.android.com/guide/topics/graphics/hardware-accel.html)进行。新模型引入DisplayList结构,记录视图渲染绘制命令。还有另一个很好的特性,时常被开发人员忽视或不正确地使用 — 视图层。

使用视图层,我们能够非屏幕缓冲区(如前面所见,应用alpha通道)渲染视图,并且能按照我们的意愿操控它。由于利用这一特性能够更快地绘制复杂动画视图,所以它主要用于动画。没有这些层次,在改变动画属性(如:x坐标、缩放、alpha值等等)后,动画视图将无效。对于复杂视图,这个无效效果都传递到所有子视图,且重绘的成本很高。在硬件支持下,使用视图层时,GPU会为视图创建纹理。有几个操作可以用于纹理,而不会破坏它,如:X / Y位置、旋转、alpha等等。所有都意味着在动画期间,可以在屏幕上绘制复杂动画视图,而完全不会破坏它。这使得动画更加顺畅。

提出在使用硬件层时需要记住几件事:

  • 清理视图。硬件层消耗有限存储元件的空间、GPU。所以仅在确实需要的时候使用(像动画),并在事后清理。
  • 如果在使用硬件层后,改变视图,硬件层无效,并在非屏幕缓冲区重绘视图。这会发生在改变那些无硬件层优化的属性上(迄今为止,仅优化:旋转、缩放、x/y、转换、轴移和alpha)。

3、其他资料

作者为说明性能分析、优化,准备很多代码来模拟情景。这些代码可以在Github代码库(https://github.com/Udinic/PerformanceDemo) 或是 Google Play(https://play.google.com/store/apps/details?id=com.udinic.perfdemo) 找到。他将不同的场景分别放到不同的Activity中,并它们编写文档,尽可能帮助理解使用这些Activity会遇到哪方面的问题。可以用工具和运行APP来阅读Activity的javadoc。

作者还推荐一些学习交流方法:

  1. 作者极力推荐大家观看YouTube上一组Android Performance Patterns视频(https://www.youtube.com/playlist?list=PLOU2XLYxmsIKEOXh5TwZEv89aofHzNCiu),其中许多短视频来自Google,讲解不同性能主题。
  2. 加入Android Performance Patterns Google+ community(https://plus.google.com/communities/116342551728637785407),这里可以与包括Google人在内的其他人一起讨论性能,分享想法、文章,和提出问题。
  3. 更有趣的链接:
    • 学习Android图形架构(http://source.android.com/devices/graphics/architecture.html)是怎样工作的。这里有你需要知道的Android怎样渲染UI的一切,讲解不同的系统元素,如:SurfaceFlinger,以及它们之间怎样相互交互的。这篇文档很长,但是值得一读。
    • 关于Google IO 2012谈话(https://www.youtube.com/watch?v=Q8m9sHdyXnE),展示绘图模型的工作原理,和如何/为什么在UI渲染时会有一个Jank。
    • Android性能研讨会(https://www.parleys.com/tutorial/part-2-android-performance-workshop), 从Devoxx 2013开始,展示Android 4.4中绘图模型的一些优化,演示不同的性能优化工具(Systrace,Overdraw等等)。
    • 关于预防性优化(https://medium.com/google-developers/the-truth-about-preventative-optimizations-ccebadfd3eb5)的长篇文章,说明这为什么不同于提早(premature)优化。由于许多开发者认为影响不明显,所以没有优化他们的部分代码。要记住一点,积少成多就是一个大问题了。如果你有机会优化一小部分代码,那怕它可能微乎其微,也不要放弃优化。
    • Android的内存管理(https://www.youtube.com/watch?v=_CruQY55HOk)这是Google IO 2011的旧视频。它仍然很有意义。它展示了Android怎样管理APP的内存的,以及怎样用工具(如Eclipse MAT)找出问题。
    • Google工程师Romain Guy所做的案例分析(http://www.curious-creature.com/docs/android-performance-case-study-1.html),怎样优化Twitter客户端。在这个案例分析中,Romain展示了他怎样在APP中找到性能问题,以及他建议如何修改它们。在一篇回帖中,展示了在重新设计同一APP后产生的其他问题。

作者希望大家已获得足够资料和更强的自信。从今天开始优化自己的APP!

作者关于性能优化的演讲视频在这里:http://www.youtube.com/embed/v3DlGOQAIbw?color=white&theme=light

转载于:https://www.cnblogs.com/figozhg/p/4945024.html

Android APP性能分析方法及工具相关推荐

  1. Android APP性能分析工具大全

    目录 官方推荐工具 第三方工具 一,官方工具 1.1,TraceView 1.2,StrictMode 1.3,Systrace 1.4,Hierarchy Viewer 1.5,AndroidStu ...

  2. Android APP性能分析工具

    会介绍以下几个主题 Systrace Traceview Memory Profiling Allocation Tracker GPU Profiling Hierarchy Viewer Over ...

  3. Android App性能分析工具(一)——GPU渲染分析

    我尽量不打错别字,用词准确,不造成阅读障碍. 一.GPU渲染速度 该工具在"开发者选项"里面,是用来展示应用每一帧中渲染消耗的时间及内容. 1.图中每一个竖条就是一帧,不同颜色代表 ...

  4. android app耗电分析方法

    这是一篇讲述应用耗电的文章,围绕 Android 电量采集机制及第二代 Battery Historian 分析工具讲述.文从数据采集.导出.环境搭建.解读报告的角度出发,从细节讲解整个流程.和大谈概 ...

  5. Android 应用性能优化(4)---Android App性能评测分析-启动时间篇

    Android App性能评测分析-启动时间篇 1.前言 随着项目版本的迭代,App的性能问题会逐渐暴露出来,而好的用户体验与性能表现紧密相关,性能问题从应用的启动优化开始,下面会根据实际app性能测 ...

  6. Android 系统性能优化(12)---MTK 平台UX性能分析方法

    1.Android UX 性能分析 UX 性能 KPI - App Launch.FPS.Game.Benchmark • 建议所有机型都做UX 测试,建立各厂家机型性能内部数据库 • 测试指标的选取 ...

  7. Atitit.提升软件Web应用程序 app性能的方法原理 h5 js java c# php python android .net

    Atitit.提升软件Web应用程序 app性能的方法原理 h5 js java c# php python android .net 1. 提升单例有能力的1 2. 减少工作数量2 2.1. 减少距 ...

  8. Android App性能评测分析

    Android App性能评测分析-启动时间篇 Android App性能评测分析-网络流量篇 Android App性能评测分析-内存篇 Android App性能评测分析-cpu占用篇 Andro ...

  9. Android APP性能优化

    转载自:https://www.cnblogs.com/qwangxiao/p/8727229.html Android APP性能优化(最新总结) 导语 安卓大军浩浩荡荡,发展已近十个年头,技术优化 ...

最新文章

  1. [原]Java 正则 多子串 匹配 替换
  2. IOS开发之手写约束
  3. 零基础如何学爬虫技术?
  4. 戛古 Kakku, Kekku-掸邦 shan state
  5. 顶会论文:基于神经网络StarNet的行人轨迹交互预测算法
  6. Oracle笔记:循环及游标
  7. vba 根据分辨率 调整窗口显示比例_2020 如何选择适合自己的显示器?小白选购电脑显示器必看,附各类型显示器高性价比选购指南分析...
  8. CF#574E. OpenStreetMap 题解
  9. angularjs directive2
  10. UIAlertControl的使用对比与UIAlertView和UIActionSheet
  11. 项目添加GPUImage
  12. 搭建Nodejs环境 创建Express应用
  13. 扇贝有道180925每日一句
  14. mysql如何创建视图语句_创建视图的语句
  15. 基于单片机的c语言交通控制器设计论文初稿,基于AT89C51单片机的交通灯控制系统设计答辩.ppt...
  16. 冒险者传说pc6java_我的世界之冒险者传说整合包游戏
  17. (Demo3D 学习笔记)案例1:自创组件,可以一键自动连接场景中的其他相关组件
  18. 《GPU编程与CG语言之阳春白雪下里巴人》 读书笔记1
  19. C#实现语音朗读功能
  20. HTTPS中的数字证书是什么?数字签名又是什么?

热门文章

  1. AMD处理器电脑使用VMware Workstation Pro 16.2.0安装macOS 10.13/10.15.3
  2. 二《计算机网络》-物理层部分
  3. linux之间怎么传文件,linux 之间互传文件
  4. ShowModal 关闭问题
  5. 终于打通了视频号跳小程序,直播带货搞起来
  6. Java后端技术学习体系—韩顺平
  7. 2020高人气小巧真无线蓝牙耳机推荐,无线蓝牙耳机选购指南
  8. 爱心c语言颜色程序代码,谁能给个爱心图案的C语言源码,帮帮我
  9. webpack配置module详解
  10. java消费轮询redis队列_redis实现队列