android性能优化

前言

性能优化本身是一个很大的主题,涵盖程序的方方面面,任何不慎的操作,都有可能对性能造成比较大的影响,要知道程序的性能是可以累加的,多处的性能低下,会影响整体的性能,其后果可能也是多方面的,本文总结了目前工作中,所需要知道的大部分性能优化点,一部分个人总结,一部分来自于互联网。但整体上,都是提纲性的,并没有列出具体的实例,因为写这方面主题的达人实在太多了,所以,我得站在巨人的肩膀上,具体细节,请参考对应的链接。

性能低下的现象

  • 游戏:界面很卡,FPS低
  • 搜索性能差
  • 服务器响应速度慢
  • OS:界面无响应

性能低下的后果:降低用户体验

  • 用户流失
  • 项目失败
  • 引发灾难

容易引发性能问题的点

  • 硬件
  • IO操作
  • 数据库
  • 网络
  • 函数调用
  • 数据结构
  • 程序逻辑
  • ….

从全局考虑

  • 硬件性能
  • 架构设计
  • 核心数据结构
  • ……

从微观考虑

小规模修改程序,提高性能:程序的性能是可以累加的

  • 简单代码设计
  • 类和函数设计:合适的数据类型和算法
    • 用快速排序代替冒泡排序
    • 用二分查找代替线性查找
  • 业务逻辑的实现
  • ……

一些观点

  • 高效代码≠更好代码≠高质量代码(易修改,易扩充,易维护)
  • 80/20法则:4%的代码占用了50%以上的运行时间
  • 随时随地进行优化 ==>将陷入无休止的优化泥潭
    • 开发阶段前期:功能都未实现,何谈优化,但在设计的时候,需要考虑到对应风险。
    • 开发阶段中后期:功能部分完善,通过现象进行模块优化
    • 开发阶段后期:功能完善,充分考虑整体性,通过现象进行系统优化
    • 后期优化无法满足性能要求----架构先天不足,只能大批量重构
  • 过分提高性能会损害程序的可读性和可维护性
  • 优先实现功能,然后再进行优化
  • 程序功能的正确性比性能更重要
  • 真正高性能的程序设计:
    • more small, more fast
    • more simple, more fast
  • ……

方法论

在进行性能优化前,确保该功能是否已基本完整。

Key Points

  • 是否考虑通过修改需求来提高性能?
  • 是否考虑通过修改整体设计提高性能?
  • 是否考虑通过来修改类的设计提高性能?
  • 在开始修改前,程序是完全正确的么?
  • 是否在修改前是否进行性能评估?
  • 是否记录了每次修改后的性能的变化?
  • 如果没有带来预期的性能提高,是否完全放弃所做的代码调整?
  • 是否对每个性能瓶颈进行不止一次的尝试?
  • 是否反复进行代码调整,直到最优?
  • ……

性能瓶颈的发现

找出瓶颈,集中火力对付占用绝大部分资源的少量代码。

途径:

  1. Code Review 通过最基本优化策略优化代码
  2. 代码性能测量 1) 通过性能Log记录函数调用时间,找出瓶颈点     LogUtil.d(TAGConstant.TAG_PERFORMANCE,"Load media info into group begin......");     longstart = System.currentTimeMillis();                  ……     LogUtil.d(TAGConstant.TAG_PERFORMANCE,“Load media info into group end, Total Time: ” + (System.currentTimeMillis() -start) + “ ms”); 2) 使用性能分析工具:     Traceview(参考:Android性能调优工具TraceView介绍) Monkey     monkeyrunner      注:后两个我个人没有使用过,不做介绍,优先推荐使用TraceView工具

如何优化

优化本身是一个很大的主题,我这是主要是针对于Android平台来说的。个人认为,优化可以分成好几部分:

  1. 一是JAVA语法层次通用的优化,如尽量使用局部变量(栈变量),IO缓冲等。
  2. 二是通用的Android性能优化,如同步改异步,各种缓存的使用等
  3. 三是应用程序内部的性能优化,如内部逻辑、数据插入及查找、数据结构的安排与组织等

以下部分针对于上述3种类型,分别进行简要说明:

基本优化策略:JAVA语法层次的优化

(以下部分来自于:http://blog.csdn.net/aomandeshangxiao/article/details/8115612#t1,具体做法请参考该连接)

  1. 类和对象使用技巧
    1. 尽量少用new生成新对象
    2. 使用clone方法生成新对象
    3. 尽量使用局部变量栈变量
    4. 减少方法调用
    5. 使用final类和final/static/private方法
    6. 让访问实例内变量的 getter/setter 方法变成final  
    7. 避免不需要的 instanceof 操作  
    8. 避免不需要的造型操作  
    9. 尽量重用对象  
    10. 不要重复初始化变量  
    11. 不要过分创建对象
  2. Java IO技巧
    1. 使用缓冲提高IO性能
    2. lnputStream比Reader高效,OutputStream比Writer高效
    3. 在适当的时候用byte替代char
    4. 有缓冲的块操作IO要比缓冲的流字符IO快
    5. 序列化时使用原子类型
    6. 在finally块中关闭stream 
    7. SQL语句
    8. 尽早释放资源
  3. 异常Exceptions使用技巧
    1. 避免使用异常来控制程序流程
    2. 尽可能重用异常
    3. 将trycatch 块移出循环  
  4. 线程使用技巧
    1. 在使用大量线程Threading的场合使用线程池管理
    2. 防止过多的同步
    3. 同步方法而不要同步整个代码段
    4. 在追求速度的场合用ArrayList和HashMap代替Vector和Hashtable
    5. 使用notify而不是notifyAll
    6. 不要在循环中调用 synchronized同步方法
    7. 单线程应尽量使用 HashMap,ArrayList
  5. 其它常用技巧
    1. 使用移位操作替代乘除法操作可以极大地提高性能
    2. 对Vector中最后位置的添加删除操作要远远快于埘第一个元素的添加删除操作
    3. 当复制数组时使用System.arraycop方法
    4. 使用复合赋值运算符
    5. 用int而不用其它基本类型
    6. 在进行数据库连接和网络连接时使用连接池
    7. 用压缩加快网络传输速度一种常用方法是把相关文件打包到一个jar文件中
    8. 在数据库应用程序中使用批处理功能
    9. 消除循环体中不必要的代码
    10. 为vectors 和 hashtables定义初始大小  
    11. 如果只是查找单个字符的话用charat代替startswith
    12. 在字符串相加的时候使用 charat()代替startswith() 如果该字符串只有一个字符的话  
    13. 对于 boolean 值避免不必要的等式判断  
    14. 对于常量字符串用string 代替 stringbuffer   
    15. 用stringtokenizer 代替 indexof 和substring  
    16. 使用条件操作符替代if cond else  结构
    17. 不要在循环体中实例化变量
    18. 确定 stringbuffer的容量  
    19. 不要总是使用取反操作符  
    20. 与一个接口 进行instanceof 操作  
    21. 采用在需要的时候才开始创建的策略  
    22. 通过 StringBuffer 的构造函数来设定他的初始化容量可以明显提升性能
    23. 合理使用 javautilVector
    24. 不要将数组声明为public static final
    25. HaspMap 的遍历
    26. array数组和 ArrayList 的使用  
    27. StringBufferStringBuilder 的区别
    28. 尽量使用基本数据类型代替对象   
    29. 用简单的数值计算代替复杂的函数计算比如查表方式解决三角函数问题
    30. 使用具体类比使用接口效率高但结构弹性降低了但现代 IDE都可以解决这个问题
    31. 考虑使用静态方法
    32. 应尽可能避免使用内在的GET/SET 方法 
    33. 避免枚举浮点数的使用   
    34. 二维数组比一维数组占用更多的内存空间大概是 10倍计算
    35. SQLite
    36. 奇偶判断

实际上,Android本身的Training文档也提供给我们很多可参考的内容,以下仅枚举一些KeyPoint,当然,有的内容是与上面的策略是重复的。

原文参考:Performance Tips

译文参考:Android应用开发者指南:性能优化(1)

其它参考:Android开发性能优化简介

总体上来说,想要写出高效代码,我们要遵循两条基本的原则:

  • 不作没有必要的工作。
  • 尽量避免内存分配。

Key Point:

  • 避免创建不必要的对象
  • 用静态代替虚拟
  • 避免内部的Getters/Setters
  • 对常量使用Static Final修饰符
  • 使用改进的For循环语法(for-each)
  • 在有内部类的情况考虑使用包权限来替代私有访问
  • 避免使用浮点数
  • 了解并使用类库
  • 合理利用Native方法

通用Android性能优化

布局优化

(原文参考:ImprovingLayout Performance

  • 尽量减少Android程序布局中View的层次,View层次越多,效率就越低
  • 使用<include/>复用布局
  • 使用ViewStub懒加载布局 (TODO:Android布局技巧:使用ViewStub提高UI性能)
  • 使用ViewHolder、Thread使ListView滚动更加流畅

其它优化点

  • 合理使用异步操作
  • 懒加载:当前不需要的数据,不要加载,即按需加载。懒加载的范围是广泛的,可以是数据,可以是View,或者其它
  • 使用缓存
    • 图片缓存:包括MemoryCache和DiskCache,推荐使用官方DEMO中的Cache

参考:DisplayingBitmaps Efficiently

  • 单例数据缓存:建立一个管理数据的类,管理所有数据,当主界面消失后,由于Application本身没有实际退出,因此,数据本身也没有释放掉,下次启动时,省去了加载数据的时间,当然,这并不是一个好的行为。
  • 使用ListView、GridView的View缓存
  • 使用Message自身的缓存,避免重复创建Message实例
  • 线程池
  • 数据池(可参考Message Pool的实现方式)
  • ……
  • 数据库优化
    • SQL优化
    • 建立索引
    • 使用事务
    • …...
  • 算法优化
    • 用快速排序代替冒泡排序
    • 用二分查找代替线性查找
    • ……
  • 数据结构使用
    • 不要全部使用ArrayList,合理使用LinkedList等易于插入和删除的集合
    • 合理使用HashMap、HashSet来提高查找性能
    • 使用SparseArray、SparseIntArray、SparseBooleanArray来替代某些特定的HashMap
    • ……
  • 其它策略
    • 可以考虑延迟处理,避免在同一时间干过多的事情

应用程序内部的性能优化

该部分的优化应该是依据程序的不同而不同,没有万般皆准的法则,目前从我做过的程序来看,实际上,上述的性能优化点基本上已经能够解决很多性能问题了。

在我所做的程序中,主要的优化手段是:

  • 程序逻辑简化:分析代码,去掉冗余逻辑
  • 数据结构的优化:对集合类的灵活使用,特别是HashMap的使用,极大的提高查找性能。
  • 批量处理原则:对于需要循环调用地方,采用批量处理

总结

性能优化本身是对代码的重构和反思过程,通过优化性能,能找出我们很多设计、逻辑上的不足。

优化的过程往往很痛苦,但在做过这个过程后,个人在编程水平、设计水平上都会有很大的提高。

很多优化的思想应该做为编码规范的一部分,需要我们反复实践,在写代码时,第一反应所得出的代码就是最优的。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏文渊之博

理解和使用SQL Server中的并行

    许多有经验的数据库开发或者DBA都曾经头痛于并行查询计划,尤其在较老版本的数据库中(如sqlserver2000、oracle 7、mysql等)。但是...

1869
来自专栏梅海峰的专栏

利用 JSON-Schema 对 Json 数据进行校验( Python 示例)

本文尝试通过 json 数据校验方法解决如下几个问题:数据没有校验,系统处于裸奔状态,导致后期维护成本高;编写一堆校验代码,混杂在业务代码中,导致代码可读性降低...

2.3K2
来自专栏大闲人柴毛毛

三句话搞定适配器模式

适配器模式的官方定义: 将一个与当前类无法兼容的接口转换成能够兼容当前类的接口。 适配器模式的大白话: 现在有一个第三方类/我们项目组中别人写的类放在我们面前,...

3276
来自专栏技术点滴

设计模式学习心得

设计模式学习心得 《设计模式:可复用面向对象软件的基础》一书以更贴近读者思维的角度描述了GOF的23个设计模式。按照书中介绍的每个设计模式的内容,结合网上搜集的...

1857
来自专栏Java技术

Java代码评审歪诗!让你写出更加优秀的代码!

架构师说, 用20个字描述代码评审的内容, 自省也省人。由于是一字一含义, 不连贯, 为了增强趣味性, 每句都增加对应的歪解。只是对常见评审的描述, 不尽之处,...

661
来自专栏Venyo 的专栏

无需数据迁移的水平分库方案

在工作中,曾经做过一个项目,采用了哈希取模的方法进行水平分库,这种方法简单高效,但是在数据库规模有所变动的时候,需要做数据迁移。本文介绍一个自己拍脑袋想出来的一...

1582
来自专栏WeTest质量开放平台团队的专栏

Go语言之三驾马车

从 Python 到 Go,远离舒适区,保持饥饿。

1041
来自专栏高性能分布式系统设计

基于 CSP 的设计思想和 OOP 设计思想的异同

Go语言推崇的CSP编程模型和设计思想,并没有引起很多Go开发者包括Go标准库作者的重视。标准库的很多设计保留了很浓的OOP的味道。本篇Blog想比较下从设计的...

3294
来自专栏技术专栏

慕课网Flask高级编程实战-9.书籍交易模型(数据库事务、重写Flask中的对象)

我们的鱼书有一个经济系统,在上传一本书的时候,将获取0.5个鱼豆。赠送一个本书的时候,再获取1个鱼豆。索要一本书的时候,消耗一个鱼豆,其中赠送和索要书籍是用户之...

542
来自专栏coding for love

JS常用设计模式解析02-策略模式

在于都本文之前,希望大家能够先阅读以下JS进阶系列03-JS面向对象的三大特征之多态这篇文章,了解JS的多态。在这篇文章,我们举了一个例子,就是选拔官员选拔合唱...

633

扫描关注云+社区