【Android开发】Android性能优化

Android性能优化

    根据Android的层次结构,性能优化也是分层次进行的,本文会分别对Application、Framework、Native、Kernel各层作总结,每层主要会从性能优化的基本思想、优化技巧、优化工具几个方面进行说明。html

第一章Android应用性能优化(概述)

    应用程序的性能问题是最明显、最容易体现的一类,表现形式也五花八门,举几个例子:node

  • 应用程序第一次启动速度慢,或者进入某一界面速度慢;
  • 启动某一有动画效果的界面,动画执行过程不流畅,或者动画执行前卡顿时间长;
  • ListView列表滑动过程当中卡顿,不流畅;
  • 应用程序自定义的某特定界面执行速度慢,例如Launcher应用桌面左右滑动效果不平滑;
  • 响应某一用户事件时长时间无响应(ANR);
  • 操做数据库时,执行大量数据的增删改查操做,执行速度慢;
  • 应用长时间运行后,随机出现卡顿现象;

       除了表现形式复杂,缘由也很复杂。以上的问题的缘由可能不仅一个,而且不少状况下并非应用自己的问题,也有多是系统其余层次有问题,只不过体如今应用层。因此说应用层老是首当其冲,开发人员在处理性能问题时,须要作的第一件事情就是判断是不是应用自身引发的性能问题,而后再对症下药;但有些时候应用自己逻辑正常,明显是系统的硬件配置不足引发,此时就要根据产品或项目需求,采起一些更加激进的方式优化性能,以弥补硬件配置的不足。android

        如下从几个不一样的角度总结一下应用程序性能优化的一些方法。算法

1、基本思想

        应用层的性能优化一般能够从如下几个方面考虑:数据库

1. 了解编程语言的编译原理,使用高效编码方式从语法上提升程序性能;编程

2. 采用合理的数据结构和算法提升程序性能,这每每是决定程序性能的关键;浏览器

3. 重视界面布局优化;缓存

4. 采用多线程、缓存数据、延迟加载、提早加载等手段,解决严重的性能瓶颈;性能优化

5. 合理配置虚拟机堆内存使用上限和使用率,减小垃圾回收频率;数据结构

6. 合理使用native代码;

7. 合理配置数据库缓存类型和优化SQL语句加快读取速度,使用事务加快写入速度;

7. 使用工具分析性能问题,找出性能瓶颈;

       固然确定还有不少其余的性能优化方法,此处仅列出一些常常会用到的方法。限于篇幅,如下会对其中一部份内容作介绍,但愿可以对你们作性能优化工做有所帮助。

2、编程技巧

(一)Performance Tips (For Java)

       Google官网上有一些关于应用程序性能提高的技巧,以前公司内也有不少总结提到过,在此简单罗列一下,详细内容能够从官网获取。

http://developer.android.com/training/articles/perf-tips.html

须要说明的是,文章列出的优化技巧主要是一些微小的性能提高,决定程序总体性能的仍然取决于程序的业务逻辑设计、代码的数据结构和算法。研发人员须要将这些优化技巧应用到平时的编码过程当中,聚沙成塔,也会对性能有很大的影响。

写出高效的代码须要遵循两条原则:

  • 不执行没必要要的操做;
  • 不分配没必要要的内存;

       两条原则分别针对CPU和内存,完成必要操做的前提下尽量的节省CPU和内存资源,天然执行效率要高。单纯这样说听起来很虚,毕竟没有一个统一的标准判断什么是必要和没必要要的,须要结合具体状况具体分析了。

     1. 避免建立没必要要的对象

       建立太多的对象会形成性能低下,这谁都知道,但是为何呢?首先分配内存自己须要时间,其次虚拟机运行时堆内存使用量是有上限的,当使用量到达必定程度时会触发垃圾回收,垃圾回收会使得线程甚至是整个进程暂停运行。可想而知,若是有对象频繁的建立和销毁,或者内存使用率很高,就会形成应用程序严重卡顿。

     2.合理使用static成员

     主要有三点须要掌握:

  • 若是一个方法不须要操做运行时的动态变量和方法,那么能够将方法设置为static的。
  • 常量字段要声明为“static final”,由于这样常量会被存放在dex文件的静态字段初始化器中被直接访问,不然在运行时须要经过编译时自动生成的一些函数来初始化。此规则只对基本类型和String类型有效。
  • 不要将视图控件声明为static,由于View对象会引用Activity对象,当Activity退出时其对象自己没法被销毁,会形成内存溢出。

       3. 避免内部的Getters/Setters

       面向对象设计中,字段访问使用Getters/Setters一般是一个好的原则,可是在Android开发中限于硬件条件,除非字段须要被公开访问,不然若是只是有限范围内的内部访问(例如包内访问)则不建议使用Getters/Setters。在开启JIT时,直接访问的速度比间接访问要快7倍。

       4. 使用for-each循环

       优先使用for-each循环一般状况下会得到更高的效率;除了一种状况,即对ArrayList进行遍历时,使用手动的计数循环效率要更高。

       5. 使用package代替private以便私有内部类高效访问外部类成员

       私有内部类的方法访问外部类的私有成员变量和方法,在语法上是正确的,可是虚拟机在运行时并非直接访问的,而是在编译时会在外部类中自动生成一些包级别的静态方法,执行时内部类会调用这些静态方法来访问外部类的私有成员。这样的话就多了一层方法调用,性能有所损耗。

一种解决这个问题的方法就是将外部类的私有成员改成包级别的,这样内部类就能够直接访问,固然前提是设计上可接受。

       6. 避免使用浮点类型

       经验之谈,在Android设备中浮点型大概比整型数据处理速度慢两倍,因此若是整型能够解决的问题就不要用浮点型。

       另外,一些处理器有硬件乘法可是没有除法,这种状况下除法和取模运算是用软件实现的。为了提升效率,在写运算式时能够考虑将一些除法操做直接改写为乘法实现,例如将“x / 2”改写为“x * 0.5”。

       7. 了解并使用库函数

Java标准库和Android Framework中包含了大量高效且健壮的库函数,不少函数还采用了native实现,一般状况下比咱们用Java实现一样功能的代码的效率要高不少。因此善于使用系统库函数能够节省开发时间,而且也不容易出错。

(二)布局性能优化

       布局直接影响到界面的显示时间。关于界面布局的性能优化在技术上并无难点,我的认为最重要的是是否定识到布局优化的重要性。起初我也会以为布局自己不会是性能瓶颈,而且也很难优化,好不容易写了复杂的布局文件,或者原生代码就是那样,并且也用log查看了setContentView的时间,彷佛没什么问题,实在是不想去研究。但实际上布局问题没有想象的那么简单。

布局的性能优化之因此重要,由于如下两个方面:

·           布局文件是一个xml文件,inflate布局文件其实就是解析xml,根据标签信息建立相应的布局对象并作关联。xml中的标签和属性设置越多,节点树的深度越深,在解析时要执行的判断逻辑、函数的嵌套和递归就越多,因此时间消耗越多;

·        inflate操做只是布局影响的第一个环节,一个界面要显示出来,在requestLayout后还要执行一系列的measure、layout、draw的操做,每一步的执行时间都会受到布局自己的影响。而界面的最终显示是全部这些操做完成后才实现的,因此若是布局质量差,会增长每一步操做的时间成本,最终显示时间就会比较长。

       那么布局如何优化?总结以下几点:

     1. 遵循一条规则:布局层次尽可能少

也就是说,在达到一样布局效果的前提下,xml文件中树的深度尽可能的潜。要作到这一点须要合理的使用布局控件:

  • 典型的状况是你可使用RelativeLayout来代替LinearLayout实现相同的布局效果;
  • 还有一种是若是布局树的A节点只有一个子节点B,而B只有一个子节点C,那么B一般是能够去掉的;
  • 合理的使用<merge>标签,若是布局X能够被include到Y中,那么须要考虑X的根节点是否能够设置为<merge>,这样在解析时会将<merge>的子节点添加到Y中,而<merge>自己不会添加。

     2. 使用Lint分析布局

       Lint是SDK中tools目录下的工具,ADT中集成了Lint的可视化控制界面。用Lint扫描应用程序,它会从不少方面对应用进行分析,并提示那些可能有缺陷的地方,其中就包含与性能相关的内容。你能够在Google官网上了解详细信息。

http://developer.android.com/tools/debugging/improving-w-lint.html

http://developer.android.com/tools/help/lint.html

     3. 使用HierarchyViewer分析布局

       HierarchyViewer(如下简称HV)也是SDK中tools目录下的工具,ADT中也集成了HV的可视化控制界面。可使用HV查看当前界面的布局,它能提供不少信息,其中有两个能够帮助咱们分析性能问题:

·           HV的树视图展示了视图控件的相互关系,能够用来检查是否有第1点中提到的状况。

·          树视图中能够显示每一个节点measure、layout、draw的时间,而且每一项用一个圆点表示其耗时是否正常,每一个圆点分别用绿色、黄色、红色表示耗时正常、警告、危险,这样就能够很方便的找到有性能瓶颈了。若是树视图中没有显示这些时间,你能够点击“Obtain layout times for tree rooted at selected node”按钮刷新界面显示。

http://developer.android.com/tools/debugging/debugging-ui.html

       4. 使用ViewStub延迟加载视图

       ViewStub是一个没有尺寸大小而且不会在布局中嵌套或渲染任何东西的轻量级的视图。若是界面中有一部分视图控件不须要当即显示,则能够将其写到一个单独的layout文件中,用ViewStub标签代替,当要真正显示这部份内容时再经过ViewStub将视图加载进来。

http://developer.android.com/training/improving-layouts/loading-ondemand.html

3、工具使用

     遵循好的编码习惯可让程序执行更有效率,可是实际运行时仍然会遇到各类各样的性能问题。幸亏有不少强大的工具能帮助咱们分析性能瓶颈,找到问题所在。如下介绍的工具想必你们已经很熟悉了,网上有不少相关文章写的都很不错,在此再也不赘述,仅对这些工具在使用时的一些关键点作一些说明。关于这些工具的详细使用方法请见网上的一篇文章:http://blog.csdn.net/innost/article/details/9008691

(一)Traceview

       作性能优化的最直接的方法,就是复现有性能问题的场景,并监控此过程当中程序的执行流程,若是可以方便的分析程序中函数的调用关系和执行时间,天然也就很容易找出性能瓶颈了。

Traceview就是用来分析函数调用过程的工具,利用它能够方便的分析性能问题。它的使用方式须要如下几步:

  • 使用Android的Debug API,或者DDMS监控程序运行过程;
  • 复现有性能问题的场景,用第1步的方法获取程序过程当中的函数调用日志文件,即trace文件;
  • 使用Traceview导入trace文件便可;

       Traceview的界面很直观,可是在分析过程当中须要特别注意如下几点:

1. Profile Panel中的各列的含义

·         Incl – 指函数自己和内部嵌套的其余函数的执行时间;

·         Excl -  指函数自己,不包含内部嵌套的其余函数的执行时间;

·         Cpu Time – 指函数执行时所占用的CPU时间片的总和,不包含等待调度的时间;

·         Real Time – 指函数执行过程的真实时间,包含等待调度的时间;

·         Cpu Time/Call – 指函数平均每次调用的CPU时间;

·         Real Time/Call – 指函数平均每次调用的真实时间;

·         Calls+Recur Calls/Total – 指函数调用的总次数+递归调用次数百分比;

·         % - 带有%的列是指函数的执行时间占总采样时间的百分比;

     2. 如何分析性能瓶颈

       首先一般须要关心的是CPU时间,能够找出程序自身的问题,真实时间会受到系统其余因素的影响。而后能够从四个方面进行分析:

1)分析有哪些函数单次执行时间长

       能够点击“Cpu Time/Call”一列,按照降序排列,并找出那些执行时间相对较长同时也是咱们关心的函数,而后再查看其函数内部的详细执行过程;

2)分析有哪些函数调用次数过多

       能够点击“Calls+RecurCalls/Total”一列,按照降序排列,并找出哪些执行次数相对较多同时也是咱们关心的函数,而后再查看其函数内部的详细执行过程;

3)分析有哪些函数总执行时间长

       有些函数的单次执行时间不是特别长,总调用次数也不是特别多,可是两者相乘得出的总的执行时间较长,能够点击“Incl Cpu Time”,按照降序排列,找出这些函数;

4)有时咱们很明确须要查看一些特定类的特定方法,能够在页面最下方的搜索条中搜索,不过好像只支持全小写输入。

       3. 提示一点:利用API或工具采样trace信息时,会禁用JIT功能,同时由于采样自己也须要占用系统资源,因此用Traceview查看函数的执行时间都要比正常运行时慢很多,咱们只要关心相对的时间消耗便可。

(二)dmtracedump

     trace文件除了能够用TraceView分析外,还能够利用另一个工具dmtracedump,它的功能也很强大。若是你以为在Traceview中查找类和函数很痛苦,不妨试试这个工具。

dmtracedump是SDK的tools目录下的可执行文件,你能够查看它的帮助信息,并执行相似以下的命令:

dmtracedump -h -g tracemap.png path-to-your-trace-file > path-to-a-html-file.html

而后就能够获得两样东西,一个是各函数调用的树状图,能够一目了然的查看函数关系;另外一个是可操做的html的文件,用浏览器打开就能够方便的查找你关心的类或函数。

(三)systrace

       Systrace是从4.1引入的一个强大的性能分析工具,依赖于Kernel的ftrace功能,能够对系统中不少重要模块,特别是图形显示模块作性能分析。它功能包括跟踪系统的I/O操做、内核工做队列、CPU负载以及Android各个子系统的运行情况等。

       Systrace的使用方法也是须要先经过Android提供的API或者DDMS开启跟踪监控模式,而后运行程序生成日志文件,最后分析日志文件便可。Systrace输出的是一个html文件,直接用浏览器查看便可。若是你使用最新版本的ADT,能够很方便的经过界面操做,不用再用命令了。更详细的内容能够在网上搜索。

4、关于性能优化的思考

       性能优化是一个很大的话题,除了讨论如何优化外,还有一个更重要的就是是否须要优化。早在几十年前,就有不少关于性能优化的讨论,而后得出一个深入的真理:优化更容易带来伤害,而不是好处,特别是不成熟的优化。在优化过程当中,你产生的软件可能既不快速,也不正确,并且还不容易被修正。

不要由于性能而牺牲合理的结构。努力编写好的程序而不是快的程序。

       可是,这并不意味着,在完成程序以前你就能够忽略性能问题。实现上的问题能够经过后期的优化而被改正,但遍及全局而且限制性能的结构缺陷几乎是不可能被改正的,除非从新编写程序。在系统完成以后再改变你的设计的某个基本方面,会致使你的系统结构病态,从而难以维护和改进。所以你应该在设计过程当中考虑性能问题。

 

       努力避免那些限制性能的设计。考虑你的代码设计的性能后果。为得到好的性能而对代码进行曲改,是一个很是很差的想法。在每次作优化以前和以后,须要对性能进行测量。

 

转自:http://rayleeya.iteye.com/blog/1961005

相关文章
相关标签/搜索