安卓效能最佳化—使用ArrayMap與SparseArray
效能最佳化是我們做開發的必須要熟練掌握的技能,所以我打算寫一個效能最佳化專題,把平時用到的一些最佳化方法記錄下來,以便忘記的時候可以快速查詢,同時也給給其他開發者提供微薄之力吧:這篇文章講述的是在一些**特定的場景**使用使用ArrayMap與SparseArray代替HashMap,提高對資料的操作;先看看官方文件的描述:
ArrayMap is a generic key->value mapping data structure that is designed to be more memory efficient than a traditional HashMap, this implementation is a version of the platform's ArrayMap that can be used on older versions of the platform.SparseArrays map integers to Objects. Unlike a normal array of Objects, there can be gaps in the indices. It is intended to be more memory efficient than using a HashMap to map Integers to Objects, both because it avoids auto-boxing keys and its data structure doesn't rely on an extra entry object for each mapping.Note that for containers holding up to hundreds of items, the performance difference is not significant, less than 50%.
從官方文件可以看出使用ArrayMap與SparseArray都要比傳統的HashMap 更有效率;但是最後有一個note,也就是當資料量達到千級以上的時候,ArrayMap與SparseArray都要比傳統的HashMap 效率更低50%;
HashMap
HashMap允許使用 null 值和 null 鍵,是基於hashing原理,我們透過put()和get()方法儲存和獲取物件。HashMap的結構:
HashMap結構
HashMap 有兩個引數影響其效能:初始容量 和載入因子。容量是雜湊表中桶的數量(預設16組),初始容量只是雜湊表在建立時的容量。載入因子 是雜湊表在其容量自動增加之前可以達到多滿的一種尺度。當雜湊表中的條目數超出了載入因子與當前容量的乘積時,則要對該雜湊表進行 rehash 操作(即重建內部資料結構),從而雜湊表將具有大約兩倍的桶數。載入因子預設值為0.75 。當我們將鍵值對傳遞給put()方法時,它呼叫鍵物件的hashCode()方法來計算hashcode,讓後找到bucket位置來儲存值物件。當獲取物件時,透過鍵物件的equals()方法找到正確的鍵值對,然後返回值物件。HashMap使用LinkedList來解決碰撞問題,當發生碰撞了,物件將會儲存在LinkedList的下一個節點中。 HashMap在每個LinkedList節點中儲存鍵值對物件。
put()方法
當兩個Key同時hash到一個值時,就會出現這樣的衝突。這個衝突主要有2種解決方法。
1、開放地址,亦即如果hash衝突,則在空閒的位置進行插入
2、hash複用,同一個hash值,鏈式地加入多個value
get()方法
HashMap還有很多方法,這裡就不一一例舉了;
透過get與put的原始碼,可以看出HashMap獲取資料是透過遍歷Entry[]陣列來得到對應的元素,在資料量很大時候會比較慢,所以在Android中,HashMap是比較費記憶體的,我們在一些情況下可以使用SparseArray和ArrayMap來代替HashMap。
SparseArray
可以看出SparseArray由兩個陣列mKeys和mValues存放;其中key的型別為int型,這就顯得SparseArray比HashMap更省記憶體一些,SparseArray在儲存和讀取資料時候,使用的是二分查詢法,那何為二分法呢?
先看一下put()方法:
在上面程式碼中有一個ContainerHelpers.binarySearch(mKeys, mSize, key)方法,這是Arrays提供了一個方便查詢的方法,也就是我們所說的“二分法”;
get()方法:
使用二分查詢法和之前的key比較當前我們新增的元素的key的大小,然後按照從小到大的順序排列好,所以,SparseArray儲存的元素都是按元素的key值從小到大排列好的。而在獲取資料的時候,也是使用二分查詢法判斷元素的位置,所以,在獲取資料的時候非常快,比HashMap快的多,因為HashMap獲取資料是透過遍歷Entry[]陣列來得到對應的元素。
其他的一些方法:
ArrayMap
ArrayMap是一個鍵值對對映的資料結構,它設計上更多的是考慮記憶體的最佳化,內部是使用兩個陣列進行資料儲存,一個陣列記錄key的hash值,另外一個陣列記錄Value值,它和SparseArray一樣,也會對key使用二分法進行從小到大排序,區別是ArrayMap的key是hash值,
可以看出ArrayMap的構造方法直接呼叫的父類的構造方法:
put()方法:
get()方法與SparseArray的一樣,就不哆嗦了:
總結
因為ArrayMap與SparseArray內部都使用了二分法進行從小到大的排序,所以當資料量很大的時候,效率至少降低一半,所以谷歌推薦資料量在千級以內時使用ArrayMap與SparseArray,資料量非常大時使用HashMap;
作者:lin_林
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/430/viewspace-2809898/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 資料結構HashMap(Android SparseArray 和ArrayMap)資料結構HashMapAndroid
- 更適合Android的集合 SparseArray/ArrayMap/ArraySetAndroid
- babel-polyfill使用與效能最佳化Babel
- SparseArray分析
- SparseArray原理分析
- 前端工程的效能與最佳化前端
- SparseArray 原始碼解析原始碼
- 效能最佳化指南:效能最佳化的一般性原則與方法
- ArrayMap是如何提高記憶體的使用效率的?記憶體
- 使用Exp和Expdp匯出資料的效能對比與最佳化
- nginx引數詳解與效能最佳化(-)Nginx
- 折騰不止!前端工程與效能最佳化前端
- 前端效能最佳化實踐方向與方法前端
- 高效能網站效能最佳化與系統架構網站架構
- 記憶體洩漏與排查流程——安卓效能優化記憶體安卓優化
- 高效能網站效能最佳化與系統架構(ZT)網站架構
- redis georadius原始碼分析與效能最佳化Redis原始碼
- 前端效能最佳化---防抖與節流--02前端
- 【效能最佳化】ORACLE資料庫效能最佳化概述Oracle資料庫
- 利用 Page Visibility API 最佳化網頁效能與使用者體驗API網頁
- Unity效能最佳化CPU最佳化Unity
- ArrayMap詳解及原始碼分析原始碼
- Android ArrayMap 原始碼詳解Android原始碼
- 面試必備:ArrayMap原始碼解析面試原始碼
- oracle 效能最佳化Oracle
- 前端效能最佳化前端
- JavaScript效能最佳化JavaScript
- HarmonyOS 效能最佳化
- MethodImpl最佳化效能
- 面試必備:SparseArray原始碼解析面試原始碼
- Android SparseArray 原始碼詳解Android原始碼
- Sql最佳化(十六) 使用陣列技術提升效能SQL陣列
- 使用智慧最佳化器提高Oracle的效能極限Oracle
- 教你使用智慧最佳化器提高Oracle效能極限Oracle
- 前端效能最佳化:使用 Web Workers 實現輪詢前端Web
- 前端效能最佳化——圖片最佳化前端
- Unity效能最佳化GPU渲染最佳化UnityGPU
- 常見效能最佳化方案與實用工具 雙 buffer