Use SparseArray to replace HashMap and sparsearrayhashmap for Android Application Performance Optimization
I. Overview recently I saw SparseArray in the project, and I studied it with curiosity. SparseArray is a class exclusive to the Android framework and does not exist in the standard JDK. It saves more memory than HashMap. In some cases, it performs better than HashMap. According to the official Q & A explanation, the main reason is that SparseArray does not need to perform auto-boxing on the key and value (encapsulate the original type as the object type, for example, encapsulating the int type as the Integer type ), structure is simpler than HashMap (SparseArray mainly uses two one-dimensional arrays to store data, one for storing key and the other for storing value) no additional data structure is required (mainly for HashMapEntry in HashMap ).
II. For more information, see SparseArray. SparseArray refers to the Sparse array. The Sparse array means that most of the content values in the array are not used (or both are zero ), only a small part of the array space is used. This results in a waste of memory space. To save memory space and do not affect the original content values in the array, we can use a compression method to represent the content of a sparse array.
Suppose there is a 9*7 array with the following content:
In this array, There are 63 spaces, but only five elements are used, resulting in a waste of 58 Element Spaces. We will use a sparse array to redefine this array as follows:
In the sparse array, the first part records the number of columns and rows of the original array, the number of elements used, and the second part records the position and content of elements in the original array. After compression, We need to declare an array with a size of 63. After compression, we only need to declare an array with a size of 6*3 and only need 18 buckets.
You can't simply say no. You can't say that the performance is good if you say that the performance is good. It's because the scorpion is pulled out and we write two test programs: Code 1:
int MAX = 100000;long start = System.currentTimeMillis();HashMap<Integer, String> hash = new HashMap<Integer, String>();for (int i = 0; i < MAX; i++) { hash.put(i, String.valueOf(i));}long ts = System.currentTimeMillis() - start;Code 2:
int MAX = 100000;long start = System.currentTimeMillis();SparseArray<String> sparse = new SparseArray<String>();for (int i = 0; i < MAX; i++) { sparse.put(i, String.valueOf(i));}long ts = System.currentTimeMillis() - start;In the above two pieces of code, we use HashMap and SpaseArray to insert 100000 pieces of data in the forward order, respectively. The data is as follows:
| # |
Code 1 |
Code 2 |
|
|
| Time |
10750 ms |
7429 ms |
|
|
| Space |
13.2 M |
8.26 M |
|
|
It can be seen that the use of SparseArray indeed saves memory than HashMap, saving about 35% of memory.
In the forward order, the time is about 33% faster than that of HashMap.
Let's change the forward order to reverse order. Try code 3:
int MAX = 100000;long start = System.currentTimeMillis();HashMap<Integer, String> hash = new HashMap<Integer, String>();for (int i = 0; i < MAX; i++) { hash.put(MAX - i -1, String.valueOf(i));}long ts = System.currentTimeMillis() - start;Code 4:
int MAX = 100000;long start = System.currentTimeMillis();SparseArray<String> sparse = new SparseArray<String>();for (int i = 0; i < MAX; i++) { sparse.put(MAX - i -1, String.valueOf(i));}long ts = System.currentTimeMillis() - start;
The running result is as follows:
| # |
Code 1 |
Code 2 |
Code 3 |
Code 4 |
| 1 |
10750 ms |
7429 ms |
10862 ms |
90527 ms |
| 2 |
10718 ms |
7386 ms |
10711 ms |
87990 ms |
| 3 |
10816 ms |
7462 ms |
11033 ms |
88259 ms |
| 4 |
10943 ms |
7386 ms |
10854 ms |
88474 ms |
From the results, we can see that SparseArray is faster than HashMap when data is inserted in the forward direction. The overhead of HashMap is almost the same whether it is in the reverse or positive direction; but the reverse insertion of SparseArray is more than 10 times slower than the forward insertion. Why? Follow up the source code and find the put method:
public void put(int key, E value) { int i = binarySearch(mKeys, 0, mSize, key); if (i >= 0) { mValues[i] = value; } else { i = ~i; if (i < mSize && mValues[i] == DELETED) { mKeys[i] = key; mValues[i] = value; return; } if (mGarbage && mSize >= mKeys.length) { gc(); // Search again because indices may have changed. i = ~binarySearch(mKeys, 0, mSize, key); } …………
Before you put the data, you will first check whether the data to be put already exists. If the data already exists, you will modify the data and add the data if it does not exist. Here is a search process, which is binarySearch. What is this? Let's look at it:
private static int binarySearch(int[] a, int start, int len, int key) { int high = start + len, low = start - 1, guess; while (high - low > 1) { guess = (high + low) / 2; if (a[guess] < key) low = guess; else high = guess; } if (high == start + len) return ~(start + len); else if (a[high] == key) return high; else return ~high; }
Soga, which is a binary search. The reason is also found. It is precisely because SparseArray uses binary search for data retrieval. Therefore, each time new data is inserted, SparseArray needs to be re-sorted. Therefore, in code 4, reverse Order is the worst case.
In addition, when the SparseArray contains a tag to be retrieved, SparseArray performs better. However, when the subscript of the search is relatively discrete, SparseArray needs to use multiple binary searches, and the performance is slower than that of the hash search method. However, according to the official documentation, the performance difference is not great, no more than 50% (For containers holding up to hundreds of items, the performance difference is not significant, less than 50% .)
Iii. Summary: In Android, memory usage is more cost-effective than CPU usage. In addition, SparseArray is not inferior in other aspects (In addition, sparseArray is also optimized when deleting data-the method of sorting arrays by delay is used. For details, refer to the official documentation.
Summary: SparseArray is a class specifically written for Hashmap such as <Interger, Object> in android to improve efficiency. Its core is binarySearch ). In Android, when we need to define
HashMap<Integer, E> hashMap = new HashMap<Integer, E>();
We can use the following method to achieve better performance.
SparseArray<E> sparseArray = new SparseArray<E>();
Refer:
- SparseArray
- Binary Search
- Sparse Matrix