Android記憶體最佳化(使用SparseArray和ArrayMap代替HashMap)

來源:互聯網
上載者:User

標籤:

在Android開發時,我們使用的大部分都是Java的api,比如HashMap這個api,使用率非常高,但是對於Android這種對記憶體非常敏感的移動平台,很多時候使用一些java的api並不能達到更好的效能,相反反而更消耗記憶體,所以針對Android這種移動平台,也推出了更符合自己的api,比如SparseArray、ArrayMap用來代替HashMap在有些情況下能帶來更好的效能提升。

介紹它們之前先來介紹一下HashMap的內部儲存結構,就明白為什麼推薦使用SparseArray和ArrayMap

HashMap

HashMap內部是使用一個預設容量為16的數組來儲存資料的,而數組中每一個元素卻又是一個鏈表的頭結點,所以,更準確的來說,HashMap內部儲存結構是使用雜湊表的拉鏈結構(數組+鏈表), 
這種儲存資料的方法叫做拉鏈法 
 
且每一個結點都是Entry類型,那麼Entry是什麼呢?我們來看看HashMap中Entry的屬性:

final K key;V value;final int hash;HashMapEntry<K, V> next;

從中我們得知Entry儲存的內容有key、value、hash值、和next下一個Entry,那麼,這些Entry資料是按什麼規則進行儲存的呢?就是通過計算元素key的hash值,然後對HashMap中數組長度取餘得到該元素儲存的位置,計算公式為hash(key)%len,比如:假設hash(14)=14,hash(30)=30,hash(46)=46,我們分別對len取餘,得到 
hash(14)%16=14,hash(30)%16=14,hash(46)%16=14,所以key為14、30、46的這三個元素儲存在數組下標為14的位置,如: 
 
從中可以看出,如果有多個元素key的hash值相同的話,後一個元素並不會覆蓋上一個元素,而是採取鏈表的方式,把之後加進來的元素加入鏈表末尾,從而解決了hash衝突的問題,由此我們知道HashMap中處理hash衝突的方法是鏈地址法,在此補充一個知識點,處理hash衝突的方法有以下幾種:

  1. 開放地址法
  2. 再雜湊法
  3. 鏈地址法
  4. 建立公用溢出區

講到這裡,重點來了,我們知道HashMap中預設的儲存大小就是一個容量為16的數組,所以當我們建立出一個HashMap對象時,即使裡面沒有任何元素,也要分別一塊記憶體空間給它,而且,我們再不斷的向HashMap裡put資料時,當達到一定的容量限制時(這個容量滿足這樣的一個關係時候將會擴容:HashMap中的資料量>容量*載入因子,而HashMap中預設的載入因子是0.75),HashMap的空間將會擴大,而且擴大後新的空間一定是原來的2倍,我們可以看put()方法中有這樣的一行代碼:

int newCapacity = oldCapacity * 2;

所以,重點就是這個,只要一滿足擴容條件,HashMap的空間將會以2倍的規律進行增大。假如我們有幾十萬、幾百萬條資料,那麼HashMap要儲存完這些資料將要不斷的擴容,而且在此過程中也需要不斷的做hash運算,這將對我們的記憶體空間造成很大消耗和浪費,而且HashMap擷取資料是通過遍曆Entry[]數組來得到對應的元素,在資料量很大時候會比較慢,所以在Android中,HashMap是比較費記憶體的,我們在一些情況下可以使用SparseArray和ArrayMap來代替HashMap。

SparseArray

SparseArray比HashMap更省記憶體,在某些條件下效能更好,主要是因為它避免了對key的自動裝箱(int轉為Integer類型),它內部則是通過兩個數組來進行資料存放區的,一個儲存key,另外一個儲存value,為了最佳化效能,它內部對資料還採取了壓縮的方式來表示稀疏數組的資料,從而節約記憶體空間,我們從源碼中可以看到key和value分別是用數組表示:

    private int[] mKeys;    private Object[] mValues;

我們可以看到,SparseArray只能儲存key為int類型的資料,同時,SparseArray在儲存和讀取資料時候,使用的是二分尋找法,我們可以看看:

 public void put(int key, E value) {        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);        ...        } public E get(int key, E valueIfKeyNotFound) {        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);        ...        }

也就是在put添加資料的時候,會使用二分尋找法和之前的key比較當前我們添加的元素的key的大小,然後按照從小到大的順序排列好,所以,SparseArray儲存的元素都是按元素的key值從小到大排列好的。 
而在擷取資料的時候,也是使用二分尋找法判斷元素的位置,所以,在擷取資料的時候非常快,比HashMap快的多,因為HashMap擷取資料是通過遍曆Entry[]數組來得到對應的元素。

添加資料
public void put(int key, E value)
刪除資料
 public void remove(int key)

or

public void delete(int key)

其實remove內部還是通過調用delete來刪除資料的

擷取資料
public E get(int key)

or

public E get(int key, E valueIfKeyNotFound)

該方法可設定如果key不存在的情況下預設返回的value

特有方法

在此之外,SparseArray還提供了兩個特有方法,更方便資料的查詢: 
擷取對應的key:

public int keyAt(int index)

擷取對應的value:

public E valueAt(int index)
SparseArray應用情境:

雖說SparseArray效能比較好,但是由於其添加、尋找、刪除資料都需要先進行一次二分尋找,所以在資料量大的情況下效能並不明顯,將降低至少50%。

滿足下面兩個條件我們可以使用SparseArray代替HashMap:

  • 資料量不大,最好在千級以內
  • key必須為int類型,這中情況下的HashMap可以用SparseArray代替:
HashMap<Integer, Object> map = new HashMap<>();用SparseArray代替:SparseArray<Object> array = new SparseArray<>();
ArrayMap

這個api的資料在網上可以說幾乎沒有,然並卵,只能看文檔了 
ArrayMap是一個<key,value>映射的資料結構,它設計上更多的是考慮記憶體的最佳化,內部是使用兩個數組進行資料存放區,一個數組記錄key的hash值,另外一個數組記錄Value值,它和SparseArray一樣,也會對key使用二分法進行從小到大排序,在添加、刪除、尋找資料的時候都是先使用二分尋找法得到相應的index,然後通過index來進行添加、尋找、刪除等操作,所以,應用情境和SparseArray的一樣,如果在資料量比較大的情況下,那麼它的效能將退化至少50%。

添加資料
public V put(K key, V value)
擷取資料
public V get(Object key)
刪除資料
public V remove(Object key)
特有方法

它和SparseArray一樣同樣也有兩個更方便的擷取資料方法:

public K keyAt(int index)public V valueAt(int index)
ArrayMap應用情境
  • 資料量不大,最好在千級以內
  • 資料結構類型為Map類型
ArrayMap<Key, Value> arrayMap = new ArrayMap<>();

【注】:如果我們要相容aip19以下版本的話,那麼匯入的包需要為v4包

import android.support.v4.util.ArrayMap;
總結

SparseArray和ArrayMap都差不多,使用哪個呢? 
假設資料量都在千級以內的情況下:

1、如果key的類型已經確定為int類型,那麼使用SparseArray,因為它避免了自動裝箱的過程,如果key為long類型,它還提供了一個LongSparseArray來確保key為long類型時的使用

2、如果key類型為其它的類型,則使用ArrayMap

Android記憶體最佳化(使用SparseArray和ArrayMap代替HashMap)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.