内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)

这里介绍Android App 内存优化中的其他优化,这里和图片优化部分目的一致,就是尽量少占用内存,这里主要从三个方面入手:

1.容器数据遍历方案选择

遍历容器是编程里面一个经常遇到的场景。在Java语言中,使用Iterate是一个比较常见的方法。可是在Android开发团队中,大家却尽量避免使用Iterator来执行遍历操作。下面我们看下在Android上可能用到的三种不同的遍历方法:

 内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第1张图片



内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第2张图片



 内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第3张图片

 

使用上面三种方式在同一台手机上,使用相同的数据集做测试,他们的表现性能如下所示:

 内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第4张图片

从上面可以看到for index的方式有更好的效率,但是因为不同平台编译器优化各有差异,我们最好还是针对实际的方法做一下简单的测量比较好,拿到数据之后,再选择效率最高的那个方式,但是为什么会出现这样的结果呢,使用index遍历容器会比iterator快呢?其实答案在于iterator是封装类,在使用它遍历过程中,会花费更多内存,更容易造成内存压力而index 使用基本型数据。

2.arrarmap 使用 

程序内存的管理是否合理高效对应用的性能有着很大的影响,有的时候对容器的使用不当也会导致内存管理效率低下。Android为移动操作系统特意编写了一些更加高效的容器,例如SparseArray,今天要介绍的是一个新的容器,叫做 ArrayMap

我们经常会使用到HashMap这个容器,它非常好用,但是却很占用内存。下图演示了HashMap的简要工作原理:

 内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第5张图片

为了解决HashMap更占内存的弊端,Android提供了内存效率更高的ArrayMap。它内部使用两个数组进行工作,其中一个数组记录key hash过后的顺序列表,另外一个数组按key的顺序记录Key-Value值,如下图所示:

 内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第6张图片

当你想获取某个value的时候,ArrayMap会计算输入key转换过后的hash值,然后对hash数组使用二分查找法寻找到对应的index,然后我们可以通过这个index在另外一个数组中直接访问到需要的键值对。如果在第二个数组键值对中的key和前面输入的查询key不一致,那么就认为是发生了碰撞冲突。为了解决这个问题,我们会以该key为中心点,分别上下展开,逐个去对比查找,直到找到匹配的值。如下图所示:

 内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第7张图片

随着数组中的对象越来越多,查找访问单个对象的花费也会跟着增长,这是在内存占用与访问时间之间做权衡交换。

既然ArrayMap中的内存占用是连续不间断的,那么它是如何处理插入与删除操作的呢?请看下图所示,演示了Array的特性:

 内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第8张图片

 内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第9张图片

很明显,ArrayMap的插入与删除的效率是不够高的,但是如果数组的列表只是在一百这个数量级上,则完全不用担心这些插入与删除的效率问题。HashMapArrayMap之间的内存占用效率对比图如下:


 内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第10张图片

HashMap相比,ArrayMap在循环遍历的时候也更加简单高效,如下图所示:

内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第11张图片

 

前面演示了很多ArrayMap的优点,但并不是所有情况下都适合使用ArrayMap,我们应该在满足下面2个条件的时候才考虑使用ArrayMap

·对象个数的数量级最好是千以内;

·数据组织形式包含Map结构。

我们需要学会在特定情形下选择相对更加高效的实现方式。

3.当心自动装箱

有时候性能问题也可能是因为那些不起眼的小细节引起的,例如在代码中不经意的“自动装箱”。我们知道基础数据类型的大小:boolean(8 bits), int(32 bits), float(32 bits)long(64 bits),为了能够让这些基础数据类型在大多数Java容器中运作,会需要做一个autoboxing的操作,转换成BooleanIntegerFloat等对象,如下演示了循环操作的时候是否发生autoboxing行为的差异(会产生没必要的对象,占用内存):

内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第12张图片



 内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第13张图片

 

Autoboxing的行为还经常发生在类似HashMap这样的容器里面,对HashMap的增删改查操作都会发生了大量的autoboxing的行为。

 内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第14张图片

为了避免这些autoboxing带来的效率问题,Android特地提供了一些如下的Map容器用来替代HashMap,不仅避免了autoboxing,还减少了内存占用:

 内存优化之其他优化(容器数据遍历方案,arraymap使用及java自动装箱)_第15张图片


到现在为止和内存相关的优化,已经介绍完了。希望读者能从这些文章中得到自己想要的。


你可能感兴趣的:(Android,App,性能优化)