Android官方开发文档Training系列课程中文版:性能优化建议

原文地址:http://android.xsoftlab.net/training/articles/perf-tips.html

本篇文章主要介绍那些可以提升整体性能的微小优化点。它与那些能突然改观性能效果的优化手段并不属于同一类。选择正确的算法与数据结构必然是我们的第一总则,但是这不是我们这篇文章要介绍的。你应该将这篇文章所提及的知识点作为编码的日常习惯,这可以提升常规代码的执行效率。

下面是书写代码的基本准则:

  • 绝不要做你不需要的工作。
  • 如果可以不申请内存就不要申请,要合理复用已有的对象。

另一个较复杂的问题就是被优化过的APP肯定是要运行在各种类型的硬件平台上。不同版本的虚拟机运行在不同的处理器上肯定会有不同的运行速度。需要特别说明的是,在模拟器上测试很少会得知其它设备的性能。在不同设备上还有一个很大的不同点就是有没有JIT(JIT的意思是即时编译器):在JIT设备上运行的最优代码并不总在没有JIT设备上有效。

为了确保APP可以在各类设备上运行良好,要确保代码在各个版本的平台上都是高效的。

避免创建不必要的对象

创建对象绝不是没有成本的。虽然分代垃圾收集器可以使临时对象的分配成本变得很低,但是内存分配的成本总是远高于非内存分配的成本。

随着更多对象的生成,你可能就开始关注垃圾收集器了。虽然Android 2.3中出现的并发收集器可能会帮到你,但是不必要的工作总是应该避免的。

因此,要避免创建不需要的对象。下面的示例可能会帮到你:

  • 如果你有个返回字符串的方法,该方法所返回的字符串总是被接在一个StringBuffer对象后面。那么就可以更改此方法的实现方式:让该字符串直接跟在StringBuffer的后面返回。这样就可以避免创建那些临时性的变量。
  • 当从字符串中提取子串时,应该尝试返回原始数据的子串,而不是创建一个副本。子串将会创建一个新的String对象,但是它与char[]共用的是同一数据。采用这种方式的唯一不足就是:虽然使用了其中的一部分数据,但是剩余的数据还都保留在内存中。

一条更为先进的法则就是,将多维数组转换为平行数组使用:

  • int数组的效率要比Integer数组的效率高的多。
  • 如果你需要实现一个用于存储(Foo,Bar)对象的数组,要记得使用两个平行的Foo[],Bar[]数组,这要比单一的(Foo,Bar)数组效率好太多。

通常来说,要尽量避免创建那些生命周期很短的临时变量。更少的对象创建意味着更低频率的垃圾回收,这会直接反应到用户体验上。

首选静态

如果不需要访问对象的属性,那么就可以将方法设置为静态方法。这样调用将会增加15%-20%的速度。这还是一个好的习惯,因为这样可以告诉其它方法一个信号:它们更改不了对象的状态。

使用常量

请先考虑以下声明:

static int intVal = 42;
static String strVal = "Hello, world!";

编译器会产生出一个类的实例化方法,名为< clinit>,它会在类首次被用到的时候执行。该方法会将值42存到intVal中,并将字符串常量表中的引用赋给strVal。当这些值被引用之后,其它属性才可以访问它们。

我们可以使用”final”关键字来改进一下:

static final int intVal = 42;
static final String strVal = "Hello, world!";

这样的话,类就不需要再调用< clinit>方法,因为常量的初始化工作被移入了dex文件中。代码可以直接引用intVal为42的值,并且访问strVal也会直接得到字符串”string constant” ,这样可以省去了查找字符串的过程。

Note: 这样优化手段仅仅适用于基本数据类型以及字符串常量,不要作用其它类型。

避免内部的get\set方法

像C++这种本地语言通常都会使用get方法来访问属性。这对C++来说是一个非常好的习惯,并且C#、Java等面向对象语言也广泛使用这种方式,因为编译器通常会进行内联访问,并且如果你需要限制访问或者调试属性的话,只需要添加代码就可以。

不过,这在Android上并不是个好习惯。方法调用的开销是非常大的。虽然为了遵循面向对象语言提供get、set方法是合理的,但是在Android中最好是可以直接访问对象的字段。

在没有JIT的设备中,直接访问对象字段的速度要比通过get方法访问的速度快3倍。在含有JIT的设备中,这个效率会达到7倍之多。

注意:如果你使用了ProGuard,那么就有了一个两全其美的结果,因为ProGuard会直接为你进行内联访问。

使用增强for循环

增强for循环可用于实现了Iterable接口的集合或数组。在集合内部,迭代器需要实现接口方法:hasNext()以及next()。

有以下几种访问数组的方式:

static class Foo {int mSplat;
}
Foo[] mArray = ...
public void zero() {int sum = 0;for (int i = 0; i < mArray.length; ++i) {sum += mArray[i].mSplat;}
}
public void one() {int sum = 0;Foo[] localArray = mArray;int len = localArray.length;for (int i = 0; i < len; ++i) {sum += localArray[i].mSplat;}
}
public void two() {int sum = 0;for (Foo a : mArray) {sum += a.mSplat;}
}

zero()方法是最慢的,因为JIT不能够对每次访问数组长度的开销进行优化。

one()方法是稍快点的。它将一切元素放入了本地变量,这样避免了每一次的查询。只有数组的长度提供了明显的性能提升。

two()方法是最快的。它使用了增强for循环。

所以应当在默认情况下使用增强for循环。

Tip: 也可以查看Josh Bloch 的 Effective Java,第46条。

考虑使用包内访问

请先思考以下类定义:

public class Foo {private class Inner {void stuff() {Foo.this.doStuff(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);}
}

上面的代码定义了一个内部类,它可以直接访问外部类的私有成员以及私有方法。这是正确的,这段代码将会打印出我们所期望的”Value is 27”。

这里的问题是:VM会认为Foo$Inner直接访问Foo对象的私有成员是非法的,因为Foo和Foo$Inner是两个不同的类,虽然Java语言允许内部类可以直接访问外部类的私有成员(PS:虚拟机与语言是两种互不干扰的存在)。为了弥补这种差异,编译器专门为此生成了一组方法:

/*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()方法时会调用上面这些静态方法。上面的代码归结为你所访问的成员属性都是通过访问器方法访问的。早期我们说通过访问器访问要比直接访问慢很多,所以这是一段特定语言形成的隐性性能开销示例。

避免使用浮点型

一般来说,在Android设备上浮点型要比整型慢大概2倍的速度。

在速度方面,float与double并没有什么区别。在空间方面,double是float的两倍大。所以在桌面级设备上,假设空间不是问题,那么我们应当首选double,而不是float。

还有,在对待整型方面,某些处理器擅长乘法,不擅长除法。在这种情况下,整型的除法与取模运算都是在软件中进行的,如果你正在设计一个哈希表或者做其它大量的数学运算的话,这些东西应该考虑到。

使用本地方法要当心

使用本地代码开发的APP并不一定比Java语言编写的APP高效多少。首先,它会花费在Java-本地代码的转换过程中,并且JIT也不能优化到这些边界。如果你正在申请本地资源,那么对于这些资源的收集能明显的感觉到困难。除此之外,你还需要对每一种CPU架构进行单独编译。你可能甚至还需要为同一个CPU架构编译多个不同的版本:为G1的ARM处理器编译的代码不能运行在Nexus One的ARM处理上,为Nexus One的ARM处理器编译的代码也同样不能运行在G1的ARM处理器上。

本地代码在这种情况下适宜采用:当你有一个已经存在的本地代码库,你希望将它移植到Android上时,不要为了改善Java语言所编写的代码速度而去使用本地代码。

如果你需要使用本地代码,那么应该读一读JNI Tips.

Tip: 相关信息也可以查看Josh Bloch 的 Effective Java,第54条。

性能误区

在没有JIT的设备中,通过具体类型的变量调用方法要比抽象接口的调用要高效,这是事实。举个例子,通过HashMap map调用方法要比Map map调用方法要高效的多,开销也少,虽然这两个实现都是HashMap。事实上速度并不会慢2倍这么多;真实的不同大概有6%的减缓。进一步讲,JIT会使两者的差别进一步缩小。

在没有JIT的设备上,通过缓存访问属性要比反复访问属性要快将近20%的速度。在JIT的设备中,属性访问的花销与本地访问的花销基本一致,所以这不是一项有多少价值的优化手段,除非你觉得这样做的话代码更易读(这对static,final,常量同样适用)。

经常估测

在开始优化之前,要确保你有个问题需要解决:要确保你可以精准测量现有的性能,否则将不能观察到优化所带来的提升。

基准点由Caliper的微型基准点框架创建。基准点很难正确获得,所以Caliper将这份很难处理的工作做了,甚至是在你没有在测量那些你想测量的地方的时候它也在工作。我们强烈的推荐你使用Caliper来创建自己的微型基准点。

你可能还发现Traceview非常有助于提升性能,不过你应该意识到Traceview工作的时候JIT并没有开启。这会错误的认为JIT会将损失掉的时间弥补回来。这尤其重要:根据Traceview所更改的结果会使实际代码运行的更快。

有关更多提升APP性能的工具及方法,请参见以下文档:

  • Profiling with Traceview and dmtracedump
  • Analyzing UI Performance with Systrace

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/478862.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

打破场景边界,PDFlux助你多领域表格提取

打破场景边界&#xff0c;PDFlux助你多领域表格提取&#xff1a;https://zhuanlan.zhihu.com/p/70092369

LeetCode 868. 二进制间距(位运算)

1. 解题 给定一个正整数 N&#xff0c;找到并返回 N 的二进制表示中两个连续的 1 之间的最长距离。 如果没有两个连续的 1&#xff0c;返回 0 。 输入&#xff1a;22 输出&#xff1a;2 解释&#xff1a; 22 的二进制是 0b10110 。 在 22 的二进制表示中&#xff0c;有三个 …

Kotlin代码检查在美团的探索与实践

背景 Kotlin有着诸多的特性&#xff0c;比如空指针安全、方法扩展、支持函数式编程、丰富的语法糖等。这些特性使得Kotlin的代码比Java简洁优雅许多&#xff0c;提高了代码的可读性和可维护性&#xff0c;节省了开发时间&#xff0c;提高了开发效率。这也是我们团队转向Kotlin的…

推荐几个出论文的好方向!

如果你准备发AI方向的论文&#xff0c;或准备从事科研工作或已在企业中担任AI算法岗的工作。那么我真诚的向大家推荐&#xff0c;贪心学院《机器学习高阶训练营》&#xff0c;目前全网上应该找不到类似体系化的课程。课程精选了四大主题进行深入的剖析讲解&#xff0c;四个模块…

开源开放 | 疾病科室、心血管系统疾病知识图谱发布,助力电子病历系统建设...

本文转载自公众号&#xff1a;OMAHA联盟。 资源发布OMAHA已建立“七巧板”医学术语集、“汇知”医学知识图谱、HiTA ICD编码服务、白皮书等资源&#xff0c;将于每月发布其中的一项或多项资源&#xff0c;敬请关注&#xff01;2009年&#xff0c;《中共中央国务院关于深化医药…

Android官方开发文档Training系列课程中文版:布局性能优化之布局层级优化

原文地址&#xff1a;http://android.xsoftlab.net/training/improving-layouts/index.html 引言 布局是直接影响用户体验的关键部分。如果实现的不好&#xff0c;那么布局很有可能会导致内存的紧张。Android的SDK包含的一些工具可以用来检查布局性能上的问题。结合本章的课程…

LeetCode 389. 找不同(位运算)

1. 题目 给定两个字符串 s 和 t&#xff0c;它们只包含小写字母。 字符串 t 由字符串 s 随机重排&#xff0c;然后在随机位置添加一个字母。 请找出在 t 中被添加的字母。 2. 解题 2.1 土办法&#xff0c;哈希map class Solution { public:char findTheDifference(string …

UAS-点评侧用户行为检索系统

背景 随着整个中国互联网下半场的到来&#xff0c;用户红利所剩无几&#xff0c;原来粗放式的发展模式已经行不通&#xff0c;企业的发展越来越趋向于精耕细作。美团的价值观提倡以客户为中心&#xff0c;面对海量的用户行为数据&#xff0c;如何利用好这些数据&#xff0c;并通…

面试官如何判断面试者的机器学习水平?

文 | 陈然知乎本文已获作者授权&#xff0c;禁止二次转载记得这大概是个三年前的问题&#xff0c;每年都会有新的答案让我持续学习。三年多前我作为最早的机器学习工程师之一加入 Tubi&#xff0c;从零开始设计招聘题目和流程&#xff0c;搭建团队&#xff0c;陆陆续续也面试了…

论文浅尝 - CVPR2020 | 基于网格特征的可视问答系统

论文笔记整理&#xff1a;李爽&#xff0c;天津大学。链接&#xff1a;https://arxiv.org/pdf/2001.03615v1.pdf动机随着“自下而上”注意力的普及&#xff0c;基于边界框(或区域)的视觉特征最近已经超越了传统的基于网格的卷积特征&#xff0c;成为视觉和语言任务的事实标准。…

Android官方开发文档Training系列课程中文版:布局性能优化之布局复用

原文地址&#xff1a;http://android.xsoftlab.net/training/improving-layouts/reusing-layouts.html 尽管Android提供了种类繁多的常用控件&#xff0c;但是有时你可能希望重用一些比较复杂的布局。如果要重用这些布局&#xff0c;可以使用< include/>标签与< merg…

:批量制作档案表,要从excel表格中将每个人的数据导入到docx档案

https://www.pythonf.cn/read/149081 Python自动将Excel数据填充到word的指定位置,Word,中 具体代码如下&#xff1a; #!/usr/bin/env python3 # -*- coding: utf-8 -*- from docxtpl import DocxTemplate from openpyxl import load_workbook import osdef replace(obj):if o…

LeetCode 1078. Bigram 分词

1. 题目 给出第一个词 first 和第二个词 second&#xff0c;考虑在某些文本 text 中可能以 “first second third” 形式出现的情况&#xff0c;其中 second 紧随 first 出现&#xff0c;third 紧随 second 出现。 对于每种这样的情况&#xff0c;将第三个词 “third” 添加到…

深度学习在OCR中的应用

背景 计算机视觉是利用摄像机和电脑代替人眼&#xff0c;使得计算机拥有类似于人类的对目标进行检测、识别、理解、跟踪、判别决策的功能。以美团业务为例&#xff0c;在商家上单、团单展示、消费评价等多个环节都会涉及计算机视觉的应用&#xff0c;包括文字识别、图片分类、目…

Android官方开发文档Training系列课程中文版:布局性能优化之按需加载View

原文地址&#xff1a;http://android.xsoftlab.net/training/improving-layouts/loading-ondemand.html 有时应用程序中会有一些很少用到的复杂布局。在需要它们的时候再加载可以降低内存的消耗&#xff0c;同时也可以加快界面的渲染速度。 定义ViewStub ViewStub是一个轻量…

千呼万唤始出来——GPT-3终于开源!

文 | 小戏编 | 小轶GPT3终于开源&#xff01;不过&#xff0c;不是官方开的&#xff08;别打我Eleuther AI推出的名为GPT-Neo的开源项目&#xff0c;于今晨4点于twitter正式宣布&#xff1a;已经开源了复现版GPT-3的模型参数&#xff08;1.3B和2.7B级别&#xff09;&#xff0c…

论文浅尝 - AAAI2020 | 迈向建立多语言义元知识库:用于 BabelNet Synsets 义元预测...

论文笔记整理&#xff1a;潘锐&#xff0c;天津大学硕士。来源&#xff1a;AAAI 2020链接&#xff1a;https://arxiv.org/pdf/1912.01795.pdf摘要义原被定义为人类语言的最小语义单位。义原知识库&#xff08;KBs&#xff09;是一种包含义原标注词汇的知识库&#xff0c;它已成…

达观数据:文档智能审阅系统

https://www.bilibili.com/video/BV1dk4y1y75W?fromsearch&seid10707410997793429063 文档智能审阅系统

美团外卖iOS多端复用的推动、支撑与思考

前言 美团外卖2013年11月开始起步&#xff0c;随后高速发展&#xff0c;不断刷新多项行业记录。截止至2018年5月19日&#xff0c;日订单量峰值已超过2000万&#xff0c;是全球规模最大的外卖平台。业务的快速发展对技术支撑提出了更高的要求。为线上用户提供高稳定的服务体验&a…

LeetCode 784. 字母大小写全排列(位运算回溯)

1. 题目 给定一个字符串S&#xff0c;通过将字符串S中的每个字母转变大小写&#xff0c;我们可以获得一个新的字符串。返回所有可能得到的字符串集合。 示例: 输入: S “a1b2” 输出: [“a1b2”, “a1B2”, “A1b2”, “A1B2”] 输入: S “3z4” 输出: [“3z4”, “3Z4”]…