android性能优化(2)—高效使用内存
一、关于内存
1.android设备和传统PC的差异:
a.物理内存太小
b.虚拟内存交换能力差
2.java基本数据类型所占字节数
boolean 8位
byte 8位
char 16位
short 16位
int 32位
long 64位
float 32位
double 64位
3.性能决定的因素
a.CPU如何操纵特定的数据类型
b.数据和指令需要占用多少存储空间
c.数据在内存中的布局
二、数据类型
1.关于数组排序时数据类型的选择
在JDK7中对Arrays类的sort方法重新进行了实现
可以看到调用了DualPivotQuicksort类的sort方法,关于DualPivotQuicksort类,可以从此处下载
该sort方法采用多路排序方式,数组中的任何元素都可以作为哨兵对象,并且不同的数据类型采用了不同的排序方法,如下:
a.int类型
b.long类型
c. char
d.short
e.byte
f.double
g.float
从这几个算法的内部来看,16位数据类型(char、short)的数组排序算法最快
2.boolean
前面提到了java8各基本数据类型中的7个,唯独没有谈到boolean,因为对boolean类型的数据排序是无意义的,不过有些时候需要对其进行存储和索引,android中提供了bitset类来对其进行处理,因为对boolean数据类型来说只需1位存储,对其分配8bit有点浪费存储空间,那么这时bitset类就派上了用场,实际上其使用的是一个long型数组来存储
但是前面说过,long类型占用64位,故为了提高效率,可以使用int类型的数组
说了这么多,就是想要告诉大家:
a.处理大量数据时,使用可以满足要求的最小的数据类型
b.避免类型转换,尽量保持类型一致
三、访问内存
a.如前所述,使用较大的数据类型进行计算会在底层(dalvik虚拟机生成的字节码)用到较多的指令,指令越多,cpu就需要做越多的工作,而代码和数据驻留在内存中,访问他们又是一个性能瓶颈。
b.因为访问内存的开销,CPU会把访问内存的内容缓存起来,cpu通常使用两级缓存,即:
一级缓存(L1)和二级缓存(L2),L1速度较快,但比L2小
c.缓存未命中:当数据或指令在缓存中找不到时,就是缓存未命中,缓存未命中的情况如下:
.指令缓存未命中
.数据缓存未命中
.写未命中
四、缓存行大小
a.缓存由行组成,每行包括几个字节
b.基本思想:
局部性原则,如果应用读取或写入到一个特定的地址,将来很可能会再次读取或写入到相同的地址或非常临近的地址
五、垃圾收集
1.内存泄漏
只有当某个对象不再被引用,它的内存才会被回收,当该被释放的对象引用仍然存在时就会发生内存泄漏。在Android中,当屏幕旋转时整个activity对象就会发生内存泄漏
2.demo
新建一个android4.1的工程
自定义一个Application类,在里面可以使用StrictMode来监测内存泄漏
可以看到StrictMode定义了以上方法来监测内存泄漏
以上就是整个自定义Application类的源码
3.引用
java定义的四种类型引用:
a.强(strong)
普通的new出来的对象都属于强引用的范畴,保持无用对象的强引用可能会导致内存泄漏
b.软(soft)
当内存有足够的空间时不会被回收,当内存吃紧时可以被任意回收,这种特性决定了软引用适合做缓存
c.弱(weak)
垃圾回收时基本会被回收,适合做一些映射,如WeakHashMap
d.虚(phantom)
很少用,如果你的应用需要知道一个对象在什么时候被回收以及在回收时执行一些操作,就可以使用该对象
4.垃圾收集
虽然可以通过调用System.gc()来提醒Android进行垃圾收集,但是垃圾收集发生的时间最终由Dalvik虚拟机决定。通过观察Logcat
可以看到发生垃圾收集时的情形:
a.GC_FOR_MALLOC:发生在堆被占满不能进行内存分配时,在分配新对象之前必须进行垃圾回收
b.GC_CONCURRENT:发生在(可能时部分的)垃圾可供回收时,通常有很多对象可以回收
c.GC_EXPLICIT:显示调用System.gc()时产生的垃圾回收
d.GC_EXTERNAL_ALLOC:一切都已在堆中分配
e.GC_HPROF_DUMP_HEAP: 发生在创建hprof时
在Android2.2及以前版本中,垃圾回收发生在主线程, 在2.2以后的版本则发生在一个单独的线程中