




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、.1优就业Android教程-Android应用程序运行的性能设计Android应用程序运行的移动设备受限于其运算能力,存储空间,及电池续航。由此,它必须是高效的。电池续航可能是一个促使你优化程序的原因,即使他看起来已经运行的足够快了。由于续航对用户的重要性,当电量耗损陡增时,意味这用户迟早会发现是由于你的程序。虽然这份文档主要包含着细微的优化,但这些绝不能成为你软件成败的关键。选择适宜的算法和数据构造永远是你最先应该考虑的事情,但这超出这份文档之外。1. 介绍写出高效的代码有两条根本的原则: 不作没有必要的工作 尽量防止存分配。2. 明智的优化这份文档是关于Android规的细微优化,所以先
2、确保你已经了解哪些代码需要优化,并且知道如何去衡量你所做修改所带来的效果(好或坏)。用开投资开发的时间是有限的,所以明智的时间规划很重要。这份文档同时确保你在算法和数据构造上作出最正确选择,同时考虑了API选择所带来的潜在影响。使用恰当的数据构造和算法比这里的任何建议都有价值,考虑API版本带来的影响会如实你选择更好的实现。当你优化Android程序时会遇到的一个棘手问题是确保你的程序能在不同的硬件平台上运行。不同版本的虚拟机在不同处理器上的运行速度各不一样。并且不是简单的设备A比设备B快或者慢,并针对一个设备与其他设备之间做出排列。特别的,模拟器上只能评测小局部可以在设备上表达的东西。有无J
3、IT的设备间也有着巨大差异:对于有JIT设备好的代码有时对无JIT的设备并不是最好的。如果你想知道程序在设备上的表现,就必须在上面进展测试3. 防止创立不必要的对象对象创立永远不会免费的。每个线程的分代GC给临时对象分配一个地址池能降低分配开销,但分配存往往需要比不分配存高的代价。如果在用户界面周期分配对象,会强制一个周期性的垃圾回收,给用户体验造成小小的停顿间隙。Gingerbread中介绍的并发回收也许有用,但应该防止不必要的工作。因此,防止创立不需要的对象实例。下面是几个例子: 如果有一个返回String的方法,他的返回值通常附加在一个StringBuffer上,改变声明和实现,这样函数
4、直接在其后面附加,而非创立一个短暂存在的临时变量。 当从输入的数据集合中读取数据时,考虑返回原始数据的子串,而非新建一个拷贝。这样你会创立一个新的对象,但是他们共享该数据的char数组。换来的是即使你仅仅使用原始输入的一局部,你也需要保证它一直存在于存中。一个更彻底的观点是将多维数组切割成一维数组: Int类型的数组比Integer类型的好。推而广之,两个平行的int数组要比一个(int,int)型的对象数组高效。这个定理对于任何根本数据类型的组合都通用。 如果需要实现存放元组(Foo,Bar)对象的容器,记住两个平行数组Foo, Bar会优于一个(Foo,Bar)对象的数组。(例外情况是:当
5、你设计API给其他代码调用时,最好用好的API设计来换取小的速度提升。但在自己的部代码中,尽量尝试高效的实现。)通常来说,尽量防止创立短时临时对象。少的对象创立意味着低频的垃圾回收。这对于用户体验产生直接的影响。4. 性能之谜前一个版本的文档给出了好多误导人的主,这里做一些澄清: 在没有JIT的设备上,调用方法所传递的对象采用具体的类型而非接口类型会更有效(比方,传递HashMap map比传递Map map调用一个方法消耗的开销小,尽管两种情况下的map都是HashMap)。但这并不是两倍慢的情形,事实上,只相差6%,而JIT使这两种调用的效率不分伯仲。 在没有JIT的设备上,缓存后的字段比
6、直接字段快大概20%。在有JIT的情况下,字段和局部消耗是一样的 。所以这里不值得优化,除非你觉得他会让你的代码更易读(对于final,static,及static final 变量同样适用).5. 用静态代替虚拟如果不需要*对象的字段,将方法设置为静态,调用会加速15%到20%。这也是一种好的做法,因为你可以通过方法声明知晓调用该方法不需要更新此对象的状态。6. 防止部的Getters/Setters在源生语言像C+中,通常做法是用Getters(i=getCount()代替直接字段(i=mCount)。这是C+中一个好的习惯,因为编译器会联这些,如果需要约束或者调试这些域的,你可以在任何时
7、间添加代码。在Android中,这是个不好的想法。虚方法调用代价比直接存取字段高昂的多。按照通常面向对象语言的做法在公共接口中使用Getters和Setters是有原因的,但应该在一个经常其字段的类中采用直接。无JIT时,直接字段大约比调用无关紧要的getter来快3倍。有JIT时(直接字段开销和局部变量是一样的),要快7倍。在Froyo版本中确实如此,但以后会在JIT中改进Getter方法的联。7. 对常量使用Static Final修饰符考虑下面类首的声明:Java代码static int intVal = 42; static String strVal = Hello, world!;
8、编译器生成一个类初始化方法clinit, 当类初次被使用时执行,这个方法将42存入intVal中,并得到类字符串常量strVal的引用。当这些值在后面被引用时,他们通过字段查找进展。我们改进实现,采用 final关键字:Java代码static final int intVal = 42; static final String strVal = Hello, world!;类不再需要clinit方法,因为常量进入了de*文件中的静态字段初始化器中。引用intVal的代码,直接调用整形值42,而strVal时也会采用相对开销较小的 string constant(字符串常量)指令替代字段查找。
9、(这种优化仅仅是针对根本数据类型和String类型常量的,而非任意的引用类型。但尽可能的将常量声明为static final类型是一种好的做法。8. 使用改进的For循环语法改进的for循环(有时被称为for-each循环)能够用于实现了iterable接口的集合类及数组中。在集合类中,迭代器促使接口hasNe*t()和ne*t()方法,在ArrayList中,计数循环迭代要快3倍(无论有没有JIT),但其他集合类中,改进的for循环语法和迭代器具有一样的效率。这里有一些迭代数组的实现:Java代码static class Foo int mSplat; Foo mArray = . publ
10、ic void zero() int sum = 0; for (int i = 0; i mArray.length; +i) sum += mArrayi.mSplat; public void one() int sum = 0; Foo localArray = mArray; int len = localArray.length; for (int i = 0; i len; +i) sum += localArrayi.mSplat; public void two() int sum = 0; for (Foo a : mArray) sum += a.mSplat; zero
11、()是当中最慢的,因为对于这个遍历中的历次迭代,JIT不能优化获取数组长度的开销。One()稍快,将所有东西都放进局部变量中,防止了查找。但仅只有数组长度促使了性能的改善。Two()是在无JIT的设备上运行最快的,对于有JIT的设备则和one()不分上下。他采用了JDK1.5中的改进for循环语法。结论:优先采用改进的for循环,但在性能要求苛刻的ArrayList迭代中考虑采用手写计数循环。9. 在私有部中,考虑用包权限替代私有权限考虑下面的定义:Java代码public class Foo private class Inner void stuff() Foo.this.doStuff(
12、Foo.this.mValue); private int mValue; public void run() Inner in = new Inner(); mValue = 27; in.stuff(); private void doStuff(int value) System.out.println(Value is + value); 需要注意的关键是:我们定义的一个私有部类(Foo$Inner)直接外部类中的一个私有方法和私有变量。这是合法的,代码也会打印出预期的Value is 27。但问题是虚拟机认为从Foo$Inner中直接Foo的私有成员是非法的,因为他们是两个不同的类,
13、尽管Java语言允许部类外部类的私有成员,编译器生成几个综合方法来桥接这些间隙。Java代码/*package*/ static int Foo.access$100(Foo foo) return foo.mValue; /*package*/ static void Foo.access$200(Foo foo, int value) foo.doStuff(value); 部类会在外部类中任何需要mValue字段或者doStuff方法的地方调用这些静态方法。这意味着这些代码将直接存取成员变量归结为通过存取器方法。之前提到存取器如何比直接慢,这例子说明,*些语言约定导致了不可见的性能问题。
14、如果你在高性能的Hotspot中使用这些代码,可以通过声明被部类的字段和成员为包权限,而非私有。不幸的是这意味着这些字段会被其他处于同一个包中的类,因此在公共API中不宜采用。10. 合理利用浮点数通常的经历是,在Android设备中,浮点数会比整型慢两倍,在缺少FPU,或是JIT的G1以及有FPU和JIT的Ne*us One中确实如此(两种设备间算数运算的绝对速度差大约是10倍).速度术语中,在现代硬件上,float和double之间并没有不同。更广泛的讲,double大约2倍大。在没有存储空间问题的桌面机器中,double的优先级高于float。但即使是整型,有些芯片拥有硬件乘法,却缺少除
15、法。这种情况下,整型除法和求模运算是通过软件实现的,考虑下当你设计Hash表,或是做大量的算术。11. 了解并使用类库除了通常的那些有限选择类库代码而非自己的原因外,考虑到系统空闲时用手写的汇编程序来替代类库方法,这可能比JIT中能生成的最好的等效Java代码还要好。典型的例子就是String.inde*Of,Dalvik用部联来替代。同样的,System.arraycopy方法比Ne*us One中有JIT的自行编码循环快9倍.12. 合理利用本地方法本地方法并不是一定比Java高效,至少,Java和native之间过渡的关联是有消耗的。而JIT并不能越过这个界限进展优化。当你分配本地资源时
16、(本地堆上的存,文件说明符等),往往很难实时的回收这些资源。同时你也需要在各个构造中编译你的代码,而非依赖JIT。甚至可能需要针对一样的架构来编译出不同版本:针对ARM处理器的GI编译的本地代码,并不能充分利用Ne*us One上的ARM,而针对Ne*us One上ARM编译的本地代码不能在G1的ARM上运行。当存在有你想部署到Android上的本地代码库时,本地代码显得尤为有用,而非为了Java应用程序的提速。结语最后:通常权衡的,先确定存在问题,再进展优化。确认你知道当前的性能,否则无法衡量你进展尝试所得到的提升。这份文档中的每个主都有基准测试作为支持。你可以在code.google.的dalvik工程
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 纺织原料新兴市场开发考核试卷
- 花生成长生成课程
- 畜牧养殖技术培训体系建设与完善考核试卷
- 大学生创新创业教育:推动高质量就业与经济发展
- 宴会活动策划书
- 职业教育的价值与实施路径
- 苏教版第27课《水》教学讲义
- 2025店面租赁合同范本
- 2025授权开发企业资源规划软件合同范本
- 2025授权调查合同模板
- 2022年12月18日浙江省(市)级机关面向基层遴选笔试真题及答案深度解析
- 慢性血栓栓塞性肺动脉高压
- 儿童早期综合发展课件
- 剪力墙平法识图讲义(PPT格式105)
- 北京中考英语词汇表(1600词汇)
- 专业工程分包业主审批表
- 药剂科终止妊娠药品管理制度
- 除草剂分类和使用方法
- 中远集团养老保险工作管理程序
- 留守儿童帮扶记录表
- 变电站第二种工作票
评论
0/150
提交评论