The use method of Sparsearray performance optimization in Android _android

Source: Internet
Author: User

The previous article looked at the horizontal level two menu and found that it used Sparsearray to replace the hashmap. So I looked up some relevant data, and I have some tests on the performance. First of all, say the principle of sparsearray.

Sparsearray (sparse array). He's an Android-specific API, and the standard JDK doesn't have it. Inside Android, the alternative to hashmap<integer,e>, Using Sparsearray saves memory space, Sparsearray also saves data with key and value. You only need to specify the type of value when you use it. and key does not need to be encapsulated as an object type.

Landlord based on the test, Sparsearray storage data consumption of memory space is indeed smaller than the hashmap. A test will be released. The data is analyzed. Let's look at the structural characteristics of both.

HashMap is a combination of arrays and linked lists, known as linked list hashes.

Sparsearray is a combination of simple arrays. Called sparse arrays, there is no extra overhead when saving data. The structure is as follows:

This is the structure of both, we need to see what the difference between the two ...

The first is to insert:

Positive sequence inserts for HashMap:

 Hashmap<integer, String>map = new Hashmap<integer, string> ();
 Long Start_map = System.currenttimemillis ();
 for (int i=0;i<max;i++) {
   map.put (i, string.valueof (i));
 }
 Long map_memory = Runtime.getruntime (). TotalMemory ();
 Long End_map = System.currenttimemillis ()-start_map;
 System.out.println ("<---map insertion time--->" +end_map+ "<---map occupied memory--->" +map_memory);

Results after execution:

 The insertion time of the <---map---
 memory occupied by >914 <---map--->28598272

Positive sequence inserts for Sparsearray:

 Sparsearray<string>sparse = new sparsearray<string> ();
 Long start_sparse = System.currenttimemillis ();
 for (int i=0;i<max;i++) {
    sparse.put (i, string.valueof (i));
 }
 Long sparse_memory = Runtime.getruntime (). TotalMemory ();
 Long end_sparse = System.currenttimemillis ()-start_sparse;
 System.out.println ("<---sparse insertion time--->" +end_sparse+ "<---memory occupied by sparse--->" +sparse_memory);

Results after execution:
<---Sparse insertion time--->611
<---sparse memory--->23281664

We can see that the efficiency of the sparsearray is higher than the hashmap efficiency in the positive sequence insertion of 100,000 data volumes. And the memory is smaller than the HashMap. The positive sequence insertion here indicates that the value of I is an increment from small to large. The sequence depends on the value of I, not how it executes inside the For loop ...

By running the results, we can find that Sparsearray is more efficient than hashmap in positive sequence insertion, and it also saves a bit of memory. There are a lot of statements on the Internet about the efficiency of both, many people will mistakenly think that sparsearray than hashmap insertion and search efficiency is faster, and others think that the hash search is certainly more than the Sparsearray in the two-point search is much faster.

In fact, I think the essential purpose of using Sparsearray when saving <Integer,Value> in Android is not because of efficiency, It's the reason for the memory. We did see the sparsearray was faster than hashmap when inserting. But this is just a positive sequence insertion. Let's look at the reverse insertion.

HASHMAP Reverse Insert:

 System.out.println ("<-------------data volume 100000 hash degree small MAP reverse insert--------------->");
 Hashmap<integer, string>map_2 = new Hashmap<integer, string> ();
 Long start_map_2 = System.currenttimemillis ();
 for (int i=max-1;i>=0;i--) {
   map_2.put (max-i-1, string.valueof (max-i-1));
 }
 Long map_memory_2 = Runtime.getruntime (). TotalMemory ();
 Long end_map_2 = System.currenttimemillis ()-start_map_2;
 System.out.println ("<---map insertion time--->" +end_map_2+ "<---map occupied memory--->" +map_memory_2);
 
 Results after execution:
 <-------------data volume 100000 map reverse Insert--------------->
 <---Map insert time--->836<--- Map Footprint Memory--->28598272

Sparsearray Reverse Insert:

System.out.println ("<-------------data volume 100000 hash degree small Sparsearray reverse insert--------------->");
sparsearray<string>sparse_2 = new sparsearray<string> ();
Long start_sparse_2 = System.currenttimemillis ();
for (int i=max-1;i>=0;i--) {
  sparse_2.put (i, string.valueof (max-i-1));
}
Long sparse_memory_2 = Runtime.getruntime (). TotalMemory ();
Long end_sparse_2 = System.currenttimemillis ()-start_sparse_2;
System.out.println ("<---sparse insertion time--->" +end_sparse_2+ "<---memory occupied by sparse--->" +sparse_memory_2);
Results after execution
<-------------data 100000 Sparsearray reverse Insert--------------->
<---Sparse insertion time--->20222 <---sparse memory--->23281664

Through the results above, we can still see that sparsearray and HashMap no matter how to insert, the amount of data at the same time, the former will save a part of the memory, but the efficiency? We can see that in the reverse insertion, Sparsearray insertion time and HashMap insertion time are far from an order of magnitude. Because Sparsearray every time you insert it, use a binary lookup to determine if the same value is being inserted. So this reverse is the worst time for sparsearray.

Sparsearray Inserts the source code we have a simple look.

 public void put (int key, E value) {int i = Containerhelpers.binarysearch (Mkeys, msize, key);//two point lookup.
      if (I >= 0) {//If the current this I exists in the array, then the same key value is inserted, just overwrite the value of values ...
    Mvalues[i] = value;
      else {//If the array does not exist inside, then the returned value must be a negative number. i = ~i;
      So you need to take the opposite number of I. The I value is less than msize indicated before this. Mkey and Mvalue arrays have been applied for space. Only the key value is deleted. Then when you save the new value again. You don't need to create additional memory space. if (i < msize && mvalues[i] = = D
        eleted) {mkeys[i] = key;
        Mvalues[i] = value;
      Return
      //When the required space is exceeded, but there are useless values in the Mkey, the GC () function needs to be invoked.
        
        if (mgarbage && msize >= mkeys.length) {GC ();
        Search again because indices may have changed.
      i = ~containerhelpers.binarysearch (Mkeys, msize, key);
      //If the required space is greater than the previously requested control, you need to open a new space for the key and value array.
        if (msize >= mkeys.length) {int n = arrayutils.idealintarraysize (msize + 1);
        A new key and value array is defined. Need greater than msize int[] Nkeys = new Int[n]; Object[] Nvalues = new Object[n];
        LOG.E ("Sparsearray", "grow" + mkeys.length + "to" + N);
        assigning to an array is a copy operation. Assigns the values of the original Mkey array and the Mvalue array to the newly opened space. The purpose is to add a new key-value pair.
        System.arraycopy (Mkeys, 0, Nkeys, 0, mkeys.length);
        System.arraycopy (mvalues, 0, nvalues, 0, mvalues.length); Assign the array to the value ... This just expands the size of the array ...
        The action to put the key value pair is not done here.
        Mkeys = Nkeys;
      Mvalues = nvalues;
      //If I has no more than msize value. Just expand the length of the Mkey.
        if (msize-i!= 0) {//LOG.E ("Sparsearray", "move" + (msize-i));
        System.arraycopy (Mkeys, I, Mkeys, i + 1, msize-i);
      System.arraycopy (Mvalues, I, mvalues, i + 1, msize-i);
      }//This is the process used to complete the put operation.
      Mkeys[i] = key;
      Mvalues[i] = value;
    msize++; 

 }
  }

This is the source code of the Sparsearray insert function. Each time you insert a method, you need to call the binary lookup. So it's very bad when you insert in reverse, Efficiency is absolutely lost to HashMap learned the data structure of everyone knows. When the map is inserted, it makes a decision about the conflict factor. There is a very good way to deal with conflicts. There is no need to traverse each value. So the efficiency of either reverse or positive insertion depends on how the conflict is handled, So the time at which the insertion is sacrificed is basically the same.

by inserting. We can still see the difference between the two.

Let's take a look at it. The lookup is hashmap first.

 System.out.println ("<-------------data volume 100000 map lookup--------------->");
 Hashmap<integer, String>map = new Hashmap<integer, string> ();
    
 for (int i=0;i<max;i++) {
    map.put (i, string.valueof (i));
 }
 Long start_time =system.currenttimemillis ();
 for (int i=0;i<max;i+=100) {
      map.get (i);
 }
 Long End_time =system.currenttimemillis ()-start_time;
 System.out.println (end_time);
 
 Results after execution
 <!---------lookup time: 175------------>

Sparsearray Search:

 System.out.println ("<-------------data volume 100000 Sparsearray lookup--------------->");
 Sparsearray<string>sparse = new sparsearray<string> ();
 for (int i=0;i<10000;i++) {
    sparse.put (i, string.valueof (i));
 }
 Long start_time =system.currenttimemillis ();
    
 for (int i=0;i<max;i+=10) {
    sparse.get (i);
 }
 Long End_time =system.currenttimemillis ()-start_time;
 System.out.println (end_time);
 Results after execution
 <!-----------lookup time: 239---------------->

I also simply tested the efficiency of the lookup. A query for a data or a few data. The difference between the two is very small. When the amount of data is 100,000, check the efficiency of 100,000 or map to a little faster. When the amount of data is 10000. But the efficiency of the map search is actually a win. Raise.

  Actually it seems to me. The main reason for using Sparsearray to replace HashMap when saving <Integer,E> is because of the memory relationship. We can see that. The amount of data saved, whether large or small, The memory used by the map is always greater than the Sparsearray. The amount of data in the 100,000 Sparsearray is 27% less than the HashMap. Memory. That is to save the memory space at the expense of efficiency. We know that Android's use of memory is extremely demanding. The maximum amount of memory allowed in the heap area is only 16M. It is very easy to oom. So the use of memory in Android is very important. So it is officially recommended to use Sparsearr Ay<e> to replace Hashmap<integer,e> The authorities did say the difference would not exceed 50%. So sacrificing some of the efficiency in exchange for memory is a good choice in Android.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.