Android容器類小結

系列文章地址:
Android容器類-ArraySet原理解析(一)
Android容器類-ArrayMap原理解析(二)
Android容器類-SparseArray原理解析(三)
Android容器類-SparseIntArray原理解析(四)android

相較於其餘設備,移動設備有本身的特色,內存小是一個很突出的問題,Google針對android設備的這一特色,開發了一套容器框架,目的就是爲了更加高效地利用內存。接下來就對這些容器進行一下總結。api

組織結構

image
以上是android中容器的實現繼承結構,簡單梳理一下:

  • ArraySet實現了SetCollections接口,在api 23中添加
  • ArrayMap實現了Map接口,在api 19中添加
  • SparseArraySparseIntArraySparseBooleanArray實現了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和剩餘的容器。經過前面的分析能夠知道,ArraySetArrayMap使用的相同的優化方式,SparseArray在進行優化的時候使用gc垃圾回收策略,故從優化方法上進行分類的話能夠分一下三類:數據結構

  • ArraySet, ArrayMap 使用數組mKeys存儲key的hash值,hash值在mKeys的位置爲index,並將value存儲到mValues數組對應下標的位置(ArrayMapkeyvalue分別在mValuesindex * 2index * 2 + 1的位置)。查找或者修改元素時,使用二分查找在mKeys中找到元素在mValues的下標,而後進行修改或者返回。
  • SparseArray 使用int類型的mKeys數組存儲int類型的鍵,下標爲index,將Object類型的value存儲在在Object類型的數組mValuesindex位置,在查找和修改時,使用二分查找在mKeys中找到元素在mValues的下標,而後進行修改或者返回。在刪除value時,SparseArray並不直接進行數組元素的移動,而是將待刪除的value標記爲DELETED狀態,在gc的過程當中將全部非DELETED狀態的元素移動到數組的最前面,從而減小二分查找的時間。
  • SparseIntArray, SparseLongArray, SparseBooleanArray 這3個容器能夠理解成專用容器,使用int類型數組和對應類型的數組;使用二分查找快速查找元素,而後進行刪除,修改,添加操做。

優化共同點與差別

雖然這些容器存儲的元素類型不一樣,可是經過分析能夠發現他們在內存優化中的共同點,接下來就分析下這些容器在優化上存在的共同點和差別。框架

共同點性能

  • 數據結構 優化

    image
    這裏的數據結構是指容器的底層存儲結構,雖然在ArrayMap中mValues的長度是mKeys的2倍,但也僅僅是數組長度上的差別,底層存儲使用的思想仍然是同樣的;int類型的數組mKeys裏的元素時按照升序進行排列的。相較於HashMap使用Node結構存儲,這樣的存儲方式使用更小的存儲空間存儲k-v,同時避免了原始數據類型的自動裝箱。

  • 查找方法 在組織結構中列出的容器,他們在進行元素查找時,都會先在mKeys數組中利用二分查找找到元素的下標index,而後使用indexmValues數組中對value進行操做。.net

  • 獲取帶插入下標 在進行元素插入時,會首先使用二分查找在mKeys數組中查找元素的下標,若是元素不存在,則二分查找會返回元素待插入位置的取反。

不一樣點

  • key的處理 ArraySet, ArrayMap底層實現時,會計算待插入元素的hash值,根據hash值,在mKeys找到待插入位置;SparseArraySparseXXXArray存儲的時候直接使用key值,不會進行hash計算。
  • null的處理 ArraySetArrayMap容許插入keynull的元素,key的hash值爲0;SparseArraySparseXXXArray存儲的時因爲直接使用int類型的數據做爲key,故不存在keynull的狀況。
  • 緩存 爲了不頻繁的內存回收,ArraySetArrayMap添加了緩存結構,SparseArraySparseXXXArray沒有緩存
  • 擴容規則 ArraySetArrayMap在進行擴容的時,容量的變化規則爲4, 8 , size * 2 / 3SparseArraySparseXXXArray使用ArrayUtils.newUnpaddedArray創建新的數據,將原來的數據拷貝到新數組中。

使用建議

雖然這些容器在Android設備上能夠更高效地利用內存,可是仍是存在使用使用限制。

  • 兼容性 在組織結構中,能夠看到,並非全部的容器都是從api 1就開始提供的,在使用具體的容器時,須要考慮應用的兼容。
  • 對性能的影響 雖然ArrayMap在刪除時不直接使用移動元素的方式刪除元素,可是在獲取數組元素等操做中仍是
  • 對數量的限制 在對元素進行查找時會使用二分查找,元素數量較大(超過1000)時,查找效率會下降,相較於HashMap只要數量不超過1000,效率最多不會降低50%。

總結

前面說了不少,其實android容器優化的根本思想就是使用int到其餘類型的映射,使用數組保存着兩個映射,用以優化HashMapk-v的存儲。這種優化適用於元素數量較少(少於1000)的狀況。

關注微信公衆號,最新技術乾貨實時推送

image
相關文章
相關標籤/搜索