系列文章地址:
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)的狀況。