ArrayMap和HashMap的記憶體佔用的區別
HashMap 原理:
HashMap 是基於雜湊表的 Map 介面實現的,內部儲存的結構是使用雜湊表的拉鍊結構(陣列+連結串列)的方式,如下圖所示
HashMap中預設的儲存大小就是一個容量為16的陣列,所以當我們創建出一個HashMap物件時,即使裡面沒有任何元素,也要分別一塊記憶體空間給它,而且,
我們再不斷的向HashMap裡put資料時,當達到一定的容量限制時(這個容量滿足這樣的一個關係時候將會擴容:HashMap中的資料量>容量*載入因子,而
HashMap中預設的載入因子是0.75),HashMap的空間將會擴大,而且擴大後新的空間大約是原來的2倍,只要一滿足擴容條件,HashMap的
的規律進行增大。假如我們有幾十萬、幾百萬條資料,那麼HashMap要儲存完這些資料將要不斷的擴容,在此過程中也需要不斷的做hash運算,這將對我們的
內存空間造成很大消耗和浪費。
用pixel手機做測試,儲存10萬條資料方法如下:
for (int i = 0; i <100000; i++) {
hashMap.put(i,"sunchao = "+i);
}
使用for迴圈,儲存10萬條資料,我們可以檢視,當前測試APP的記憶體動態圖如下:
測試HashMap儲存10萬條資料得出的記憶體動態圖:
從抓取的APP的動態的圖,我們可以發現,HashMap的消耗的最大記憶體達到了103.5MB。
ArrayMap的工作原理:
為了解決HashMap佔記憶體的弊端,Android提供了記憶體效率更高的ArrayMap。它內部使用兩個陣列進行工作,其中一個數組記錄
key換成hash值過後的順序列表,另外一個數組按key的順序記錄Key-Value值,如下圖所示
可以看出ArrayMap採用的是Key-Values對映資料結構。
ArrayMap中主要儲存的資料的是兩個資料
mHashs中儲存出的是每個key的hash值,並且在這些key的hash值在陣列當中是從小到大排序的。mArray的陣列長度是mHashs的兩倍,每兩個元素分別
是key和value,這兩元素對應mHashs中的hash值。在我們使用put方法進行儲存資料的過程中,空間不夠時,會發生如下擴容
BASE_SIZE = 4,先判斷oSize值是否大於等於8,如果是則n=oSize*1.5,否則就判斷是否大於等於4,是則n=8個,否則n=4個。
然後把老的陣列中的資料複製到了新的陣列當中如下
allocArrays和freeArrays方法中,。這兩個方法的作用基本上就是當長度不夠用,我們需要廢棄掉老的陣列,使用新的陣列的時候,
把老的陣列(包含mHashes和mArray)的資料新增到oArray當中,然後把oldArray賦值給mBaseCache(4個長度),如果再有
新的ArrayMap建立陣列空間的時候,如果還是申請4個的空間,那麼優先使用快取下來的這個。
用pixel手機做測試,同樣儲存10萬條資料方法如下:
for (int i = 0; i <100000; i++) {
arrayMap.put(i,"sunchao = "+i);
}
使用for迴圈,儲存10萬條資料,我們可以檢視,當前測試APP的記憶體動態圖如下:
測試ArrayMap儲存10萬條資料得出的記憶體動態圖:
從抓取的APP的動態的圖,我們可以發現,ArrayMap的消耗的最大記憶體達到了91.4MB。
從中可以得出結論: 在儲存資料方面ArrayMap確實要比HashMap消耗的記憶體小。HashMap初始值16個長度,每次擴容的時候,
直接申請雙倍的陣列空間。ArrayMap每次擴容的時候,如果size長度大於8時申請size*1.5個長度,大於4小於8時申請8個,小於
4時申請4個。ArrayMap其實是申請了更少的記憶體空間,但是擴容的頻率會更高,並且ArrayMap採用了一種獨特的方式,能夠重複
的利用因為資料擴容而遺留下來的陣列空間,而HashMap沒有這種設計。