Analysis of LRUCache Source code

Source: Internet
Author: User
Tags delete key

In mobile device development, the use of effective caching techniques is necessary due to the limited memory of mobile devices ( mobile phones, etc. ) . Android provides a cache tool class LruCache, in the development we will often use, the following we will be specific analysis of LruCache.

LruCache Cache Data is a strong reference to holding data to hold a certain amount of data . Each time a data is used ( fetch ) , the data is moved ( a saved data ) The head of the queue, when adding a new data to the cache, if the cache is full, the last data in the cache queue is automatically deleted, so that the deleted data is not strongly referenced and can be recycled by GC .

1. First, let's take a look at the LRUCache constructor:

Public LruCache (int maxSize) {          if (maxSize <= 0) {              throw new IllegalArgumentException ("maxSize <= 0");          }          this.maxsize = maxSize;          This.map = new linkedhashmap<k, v> (0, 0.75f, true);  }

1.1 need to pass in a maxSizewhen creating LruCache , which means LruCache Specifies the maximum storage space. Here I would like to ask if maxSize refers to the number of cached data Objects , or the amount of memory consumed by the cache data ?

In fact, can be the number of cached data , you can also make the amount of memory consumed by the cache data , of course, it can be other . What the hell is it? , I need to see you. LruCache How to override this method : sizeof (K key, V value), let's look at LRUCache 's sizeOf function source code:

protected int sizeOf (K key, V value) {//Subclass overrides this method to calculate the amount of data that is consumed by the cache for each saved return 1;//returns 1 by default, which means that the number of caches by default is the total number of cached data (each Data is 1).}

So if I use LruCache to save the bitmap picture , and I want the cache capacity to be 4M . , the reference code is as follows:

int cacheSize = 4 * 1024 * 1024; 4MiBnew lrucache<string, bitmap> (cacheSize) {<span style= "White-space:pre" ></span> @Override <span style= "white-space:pre" ></span>protected int sizeOf (String key, Bitmap Bitmap) {//Calculate the memory size of each cached picture <span style= "White-space:pre" ></span>return bitmap.getrowbytes () * Bitmap.getheight (); <span style= " White-space:pre "></span>}};

In the 1.2 LruCache constructor We notice that the Linkedhashmap class, we know that Linkedhashmap is a key-value pair of data , and can maintain the corresponding order of these data, the source code of Linkedhashmap initialization is as follows:

Call HashMap's construction method to construct the underlying array public linkedhashmap (int initialcapacity, float loadfactor) {super (initialcapacity          , Loadfactor);    Accessorder = false; The elements in the list are sorted by default in insert order}

Where initialcapacity represents the load load factor, which is used when the HashMap is expanded. Another parameter is that the Loadfactor,linkedhashmap internally maintains a two-way loop linked list, the list of two kinds of lists, with the value of the Loadfactor parameter to distinguish, when the loadfactor is False , the order in the insertion sequence, when when Loadfactor is true , the flags are sorted in order of access. the Linkedhashmap constructor in LruCache passed true, which implements the saved data in a certain order, sorted in order of access, With an existing data , The data is moved to the head of the data queue .

To learn more about Linkedhashmap, see Linkedhashmap source profiling: http://blog.csdn.net/ns_code/article/details/37867985

2. LruCache how , when to determine if the cache is full , and to remove the infrequently used data ?

       in lrucache There's a way. :trimtosize () is used to detect whether the current is full , if full to automatically remove a data, until discontent :

public void trimtosize (int maxSize) {//By default incoming is the value above said maximum capacity this.maxsize while (true) {///dead        Cycle. Guarantee until the discontent K key;        V value; Synchronized (this) {//Thread safety guarantee if (Size < 0 | | (Map.isempty () && size! = 0)) {throw new IllegalStateException (GetClass (). GetName () +. SizeOf () is reporting Inco            Nsistent results!);            if (size <= maxSize) {//If dissatisfied, jump out of the loop break;                } map.entry<k, v= "" > toevict = Map.eldest ();//Remove the last data (least commonly used data) if (toevict = = null) {            Break            } key = Toevict.getkey ();            Value = Toevict.getvalue ();        Map.Remove (key);//Remove this data size-= safesizeof (key, value);//capacity Reduction evictioncount++;//Update number of automatically removed data (number of times) } entryremoved (True, key, value, NULL);//To notify that the data has been removed, if you need to know when a data is removed you need to write this method entryremoved}} 

       above source I gave a description, Very well understood. Note Here is trimtosize This method is public Description We can actually call this method's . Then I trimtosize When is this method called

TrimToSize This method in the LruCache inside the multiple methods will be used to detect whether it is full , such as in the LruCache The method of adding a new data inside the put , and when getting a data through the get (K key) method , etc. will call trimtosize to detect it once .

3. Let's look at the put method of LruCache

The put method is to add a new piece of data to the LRUCache cache:

Public final V put (K key, V value) {//Add a new data    if (key = = NULL | | value = = NULL) {        throw new NullPointerException ( Key = = NULL | | Value = = null);    }     V previous;    Synchronized (this) {        putcount++;        Size + = safesizeof (key, value); Size plus the previous of the pre-put object        = Map.put (key, value);        if (previous! = NULL) {///If an object with key is previously present, size should be subtracted from the original object sizes--            = safesizeof (key, previous);}    }     if (previous! = NULL) {//Add duplicate position data, remove old data        entryremoved (False, key, previous, value);    }     TrimToSize (maxSize);//each new Join object needs to call TrimToSize to detect if the cached data is full    return previous;}

We see that the above approach involves thread-safe addition to the Synchronized keyword, which shows that LRUCache is thread-safe .

4. Take a look at The Get method of LRUCache :

The Get method returns the corresponding item by key

Let's look at the source code for get :

Public final V get (K key) {//Get a data     if (key = = null) {         throw new NullPointerException (key = = null);     }     v MapValue ;     synchronized (this) {        mapvalue = Map.get ( key);         if (mapvalue! = null) {//Get this data              hitcount++;//number of acquisition data              return mapvalue;//successfully obtained this data         }         misscount++;//the number of data failures}/* if missing, an attempt was made to create an object, where the method returns NULL, There is no way to implement a method that creates an object if it is necessary to create an object method can override the Create method. Because the memory cache does not hit when the picture is cached, it goes to <span style= "font-family:arial, Helvetica, Sans-serif;" > file cache to fetch or download from the network, so do not need to create. */</span>    v createdvalue = Create (key);//try creating this data  &nbsP;  if (Createdvalue = = null) {        return null;//failed to create data      }     synchronized (This) {//Join this re-created data          createcount++;//new Data Creation         mapvalue = Map.put (key, Createdvalue);          if (mapValue! = null) {    //if Mapvalue is not empty, undo the put operation of the previous step.             map.put (Key, MapValue);         } else {             size + = safesizeof (key, Createdvalue);        }     }     if (Mapvalue! = null) {         Entryremoved (False, Key, Createdvalue, mapvalue);          return mapvalue;    } else {         TrimToSize (maxSize);//detection is full         return createdvalue;     }}

returns the corresponding itemby key , or creates a return item. The corresponding item will be moved to the head of the queue if item 's value is not cache or it cannot be created, it returns null.

We saw in the above source a create (key) method, we look at the source of the Create method:

Protected V Create (K key) {return null;}

You can see that the source code returns a nullby default, and we parse the get codes above,

V Createdvalue = Create (key);// Try to create this data

if (Createdvalue = = null) {

Return null;// failed to create data

}

The code determines that if create returns null,get returns NULL, indicating that the query is no longer Cached in the cache, If it is not found in the file cache, it will be downloaded again on the network.

SoCreatewill always returnNULL,LruCacheWhy shouldcreatmethod, let's analyze ifCreateno remorse .NULLwhat will be handled, see the source know he will returnCreatedvalue added toMapcollection, and then theCreatedvalue returned to the user. From the above analysis can be known, although the source ofcreatmethod returns the horizontalNULL, but we can rewriteCreatemethod to recreate data that does not already exist. Of course, this is not the case and will be downloaded again from the network when the corresponding cache is not found.

5. Finally, take a look at the remove method:

/**  * Delete key corresponding cache entry, return the corresponding value*/public      final V remove (K key) {          if (key = = null) {              throw new Nullpointer Exception ("key = = null");          }            V previous;          Synchronized (this) {              previous = Map.Remove (key);              if (previous! = null) {                  Size-= safesizeof (key, previous);}          }            if (previous! = null) {              entryremoved (false, key, previous, NULL);          }            return previous;      

The Remove method removes the corresponding cache entry for key and returns the corresponding value. So we can proactively remove the cached data from the cache.

Introduction to Here, LRUCache's main code is complete,

Here's a cache implementation of a network picture for caching downloads:

public class Bitmapcache implements Imagecache {private static lrucache<string, bitmap> mcache;public Bitmapcache ( {if (Mcache = = null) {//Gets the maximum amount of available memory, using memory exceeding this value causes outofmemory exceptions.      //LRUCache pass through the constructor function to the cache value, in kilobytes.      int maxmemory = (int) (Runtime.getruntime (). MaxMemory ());      Use 1/8 of the maximum available memory value as the size of the cache.      int cacheSize = MAXMEMORY/10;  Mcache = new lrucache<string, bitmap> (cacheSize) {@Overrideprotected int sizeOf (String key, Bitmap Bitmap) {return B Itmap.getrowbytes () * Bitmap.getheight ();}};} @Overridepublic Bitmap getbitmap (String URL) {return mcache.get (URL);} @Overridepublic void Putbitmap (String url, Bitmap Bitmap) {mcache.put (URL, Bitmap);}}

In the app, you can get or add picture data through Getbitmap, Putbitmap. When the call to Getbitmap returns null , we need to re-download it on the network.





Analysis of LRUCache Source code

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.