android应用性能优化的读书笔记

第四章高效使用内存

注意数据类型:

java char是16为(UTF-16)
java long 为64(c的为32,long long 为64)

性能取决于以下因素

  • CPU如何操作特定的数据类型
  • 数据和指令需要占用多少存储空间
  • 数据在内存中的布局

各种数据类型使用排序算法耗时:(使用Arrays.sort()排序,找最小,求和)

其中使用short最佳。总结规律:

  • short数组的排序优于其他类型数组
  • 处理64为类型比32位慢。

16位数组排序远远快于32位或者64位的原因
int和long使用某些版本的快速排序,而short数组使用的是计数排序。分析arrays.java的源码,看看每种数据类型的数组是如何排序。
short的范围:-32768~32767

关于Boolean类型

boolean实际只需要一位,但实际java分配了8位。为此,定义了BitSet类(系统源码提供)进行改善。

关于Bitset

在此基础上进行改善:值提取部分类的代码,使用int来代替long来维护数组。
详细使用:java BitSet

面试题中也常出现

比如:统计40亿个数据中没有出现的数据,将40亿个不同数据进行排序等。
又如:现在有1千万个随机数,随机数的范围在1到1亿之间。现在要求写出一种算法,将1到1亿之间没有在随机数中的数求出来
programming pearls上也有一个关于使用bitset来查找电话号码的题目。
Bitmap的常见扩展,是用2位或者更多为来表示此数字的更多信息,比如出现了多少次等。

SparseBooleanArrays来改善大部分位被设为相同的值。使用策略模式在适当的时候进行调用。
关于:Android编程之SparseArray<E>详解
## Android性能优化之使用SparseArray代替HashMap

几条规则:

  • 处理大量数据的时候,尽量用小的数据类型进行代替
  • 避免类型转换
  • 有更好的性能就推倒重来

排布数据

将类换成数组,将每个属性用数组缓存,每个数组都相对应。如:

1
2
3
4
5
6
7
8
9
public class Person{
short a;
short b;
}
# 用两个数组进行维护
arr1[index]=a;
arr2[index]=b;
代替
arr3[index]=new Person();

另外一点:要避免getA()和getB()的使用的开销,设为共有就好了。
注意:这种优化并不能总是派上用场,需要知道代码使用的正确方式,才可以更好的优化代码。

使用StrictMode来检测没有关闭资源导致的泄漏问题

可检测的范围:

  • SQLite对象:游标没有关闭的泄漏。
  • Acitivty泄漏
  • 对象没有关闭的泄漏(实现Closeable接口的所有类)
  • Disk Reads 磁盘读和Disk Writes 磁盘写
  • Network access 网络访问
  • Custom Slow Code 自定义的运行速度慢的代码分析

此功能在开发和测试阶段开启,应用发布的时候需要禁用

详细使用:
# Android最佳实践之:StrictMode介绍
StrictMode 详解

  • 启动:
    只需要打开一次就可以。在Activity/ApplicationonCreate()方法上启用。

  • 使用:

    违反情况可以记录在LogCat中或者存储在DropBox中(android.os.DropBox)服务中

  • 忽略某些规则(指定代码不产生警告)

    在应用程序的主线程中去快速读写磁盘其实不会对应用的性能产生太大的影响,

1
2
3
4
5
6
StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy();
  StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder(old)
  .permitDiskWrites()
  .build());
  doCorrectStuffThatWritesToDisk();
  StrictMode.setThreadPolicy(old);

这里首先用old来保存了当前的策略规则,然后doCorrectStuffThatWritesToDisk();这里,执行了一些向磁盘快速读写的操作,最后又重新启用了这些规则

  • 关闭:
    <Application>设置属性:android:debuggable,然后在代码中设置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ApplicationInfo appInfo = context.getApplicationInfo();
int appFlags = appInfo.flags;
if ((appFlags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
//虚拟机的策略(检测内存泄露,资源是否关闭)
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.penaltyDeath()
.build());
//线程策略(磁盘读写,网路等)
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.penaltyDialog()
.build());

可使用detectAll()来代替全部设置。

  • 相关的策略模式:

    线程策略(ThreadPolicy),虚拟机策略(VmPolicy)。虚拟机策略(VmPolicy)能检查内存泄漏

  • 方法解释:

    • .detectCustomSlowCalls 发现UI线程调用的那些方法执行得比较慢. 还有时间输出,但需要在测试的方法中进行标记:StrictMode.noteSlowCall("slowCall 2");
    • penaltyDeath(),当触发违规条件时,直接Crash掉当前应用程序
    • setClassInstanceLimit(),设置某个类的同时处于内存中的实例上限,可以协助检查内存泄露