系列文章地址:
Android容器类-ArraySet原理解析(一)
Android容器类-ArrayMap原理解析(二)
Android容器类-SparseArray原理解析(三)
Android容器类-SparseIntArray原理解析(四)android
相较于其余设备,移动设备有本身的特色,内存小是一个很突出的问题,Google针对android设备的这一特色,开发了一套容器框架,目的就是为了更加高效地利用内存。接下来就对这些容器进行一下总结。api
ArraySet
实现了Set
和Collections
接口,在api 23中添加ArrayMap
实现了Map
接口,在api 19中添加SparseArray
,SparseIntArray
,SparseBooleanArray
实现了Cloneable
接口,在api 1中添加SparseLong
实现了Cloneable
接口,在api 18中添加从**功能
**上划分,能够将以上容器划分为两类:数组
存储元素
ArraySet
优化了HashSet
对元素的存储
缓存
存储键值对 相较于HashMap
,具体的优化方向以下:
ArrayMap
优化了HashMap
存储Object --> Object
的键值存储;
SparseArray
优化了int --> Object
的键值存储;
SparseIntArray
优化了int --> int
的键值存储;
SparseBooleanArray
优化了 int --> boolean
的键值存储;
SparseLongArray
优化了 int --> long
的键值存储。
微信
从组织结构能够看出,能够将这些容器分为3类:ArraySet
,ArrayMap
和剩余的容器。经过前面的分析能够知道,ArraySet
和ArrayMap
使用的相同的优化方式,SparseArray
在进行优化的时候使用gc
垃圾回收策略,故从优化方法上进行分类的话能够分一下三类:数据结构
ArraySet
, ArrayMap
使用数组mKeys
存储key
的hash值,hash值在mKeys
的位置为index
,并将value存储到mValues
数组对应下标的位置(ArrayMap
中key
和value
分别在mValues
的index * 2
和index * 2 + 1
的位置)。查找或者修改元素时,使用二分查找在mKeys
中找到元素在mValues
的下标,而后进行修改或者返回。SparseArray
使用int
类型的mKeys
数组存储int
类型的键,下标为index
,将Object
类型的value
存储在在Object
类型的数组mValues
的index
位置,在查找和修改时,使用二分查找在mKeys
中找到元素在mValues
的下标,而后进行修改或者返回。在删除value
时,SparseArray
并不直接进行数组元素的移动,而是将待删除的value
标记为DELETED
状态,在gc
的过程当中将全部非DELETED
状态的元素移动到数组的最前面,从而减小二分查找的时间。SparseIntArray
, SparseLongArray
, SparseBooleanArray
这3个容器能够理解成专用容器,使用int
类型数组和对应类型的数组;使用二分查找快速查找元素,而后进行删除,修改,添加操做。虽然这些容器存储的元素类型不一样,可是经过分析能够发现他们在内存优化中的共同点,接下来就分析下这些容器在优化上存在的共同点和差别。框架
共同点性能
数据结构 优化
ArrayMap
中mValues的长度是mKeys的2倍,但也仅仅是数组长度上的差别,底层存储使用的思想仍然是同样的;int
类型的数组mKeys
里的元素时按照升序进行排列的。相较于HashMap
使用Node
结构存储,这样的存储方式使用更小的存储空间存储k-v
,同时避免了原始数据类型的自动装箱。 查找方法 在组织结构中列出的容器,他们在进行元素查找时,都会先在mKeys
数组中利用二分查找找到元素的下标index
,而后使用index
到mValues
数组中对value
进行操做。.net
获取带插入下标 在进行元素插入时,会首先使用二分查找在mKeys
数组中查找元素的下标,若是元素不存在,则二分查找会返回元素待插入位置的取反。
不一样点
key
的处理 ArraySet
, ArrayMap
底层实现时,会计算待插入元素的hash值,根据hash值,在mKeys
找到待插入位置;SparseArray
和SparseXXXArray
存储的时候直接使用key
值,不会进行hash计算。null
的处理 ArraySet
和ArrayMap
容许插入key
为null
的元素,key
的hash值为0;SparseArray
和SparseXXXArray
存储的时因为直接使用int类型的数据做为key
,故不存在key
为null
的状况。ArraySet
和ArrayMap
添加了缓存结构,SparseArray
和SparseXXXArray
没有缓存ArraySet
和ArrayMap
在进行扩容的时,容量的变化规则为4, 8 , size * 2 / 3
,SparseArray
和SparseXXXArray
使用ArrayUtils.newUnpaddedArray
创建新的数据,将原来的数据拷贝到新数组中。虽然这些容器在Android设备上能够更高效地利用内存,可是仍是存在使用使用限制。
ArrayMap
在删除时不直接使用移动元素的方式删除元素,可是在获取数组元素等操做中仍是HashMap
只要数量不超过1000,效率最多不会降低50%。前面说了不少,其实android容器优化的根本思想就是使用int
到其余类型的映射,使用数组保存着两个映射,用以优化HashMap
对k-v
的存储。这种优化适用于元素数量较少(少于1000)的状况。