Android LRUCache Source parsing

Source: Internet
Author: User

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, which we will use frequently in development, and how he is implemented.

There are java files defined for LRUCache in the package Android.util pack. To be able to understand LRUCache accurately, let's take a look at the original note:

* A cache that holds strong references to A limited number of values. Each time * A value is accessed, it's moved to the head of a queue. When a value was * added to a full cache, the value at the end of this queue is evicted and could * become eligible for Garba GE Collection.
Simple translation: LRUCache cache data is saved with a strong reference to holding dataA certain numberData. Each time a data is used, the data is moved to the head of the queue where the data is stored, and when a new data is added to the cache, if the cache is full,is automatically deletedThe last data in this cache queue so that the deleted data is not strongly referenced and can be recycled by GC.

From the above translation, you can know how LRUCache works. Here's a step-by-step explanation of his implementation:

(1) How to implement the saved data is in a certain order, and the use of an existing data, the data will be moved to the head of the data queue. The Linkedhashmap is used here.

We know that Linkedhashmap is saving a key-value pair of data, and can maintain the corresponding order of the data. Generally, the stored data can be guaranteed in the order in which they are deposited or in the order in which they are used. Below is a look at how LRUCache is constructed:

    Public LruCache (int maxSize) {//Specify the number of cached data        if (maxSize <= 0) {//must be greater than 0            throw new IllegalArgumentException (" MaxSize <= 0 ");        }        This.maxsize = maxSize;        This.map = new linkedhashmap<k, v> (0, 0.75f, true);//Create a linkedhashmap and sort by the order in which the data is accessed        }
(2)As you can see from the construction method above, you need to specify the amount of data that is cached when you create a lrucache. Here's a detailed explanation of what the "quantity" of this cached data means: What is the number of cached data objects, or the amount of memory that is consumed by the cached data?

The answer is: all. This can be the number of cached data, or the amount of memory that can be consumed by the cached data, or it can be other. What is it that needs to see your lrucache How to override this method: SizeOf (K key, V value)

    protected int sizeOf (K key, V value) {//Subclass overrides this method to calculate the amount of memory that is consumed by each saved data return        1;//returns 1 by default, indicating: By default, the number of caches refers to the total number of cached data (1 per data).    }
So what if I use LRUCache to save the bitmap picture, and I want the cache capacity to be 4M? In the original description, Android gives an example:

* <p>by default, the cache size is measured in the number of entries. Override * {@link #sizeOf} to size the cache in different units. For example, this cache * was limited to 4MiB of bitmaps: * <pre>   {@code *   int cacheSize = 4 * 1024 * 1024; /4MiB *   lrucache<string, bitmap> bitmapcache = new lrucache<string, bitmap> (cacheSize) {// Save Bitmap LRUCache, capacity is 4M *       protected int sizeOf (String key, Bitmap value) {*           return value.getbytecount ();// Calculate the memory size of each cached picture *       } *   }}</pre>
(3)So how does LRUCache, when to tell if the cache is full, and to remove the infrequently used data?

In fact, in LRUCache there is a method: TrimToSize () is used to detect whether the current is full, if full to automatically remove a data, until the dissatisfaction:

    public void trimtosize (int maxSize) {//By default, the value passed in is the maximum capacity stated above This.maxsize while (true) {//Dead loop. Guaranteed until you're dissatisfied.            K key;            V value; Synchronized (this) {//Thread safety guarantee if (Size < 0 | | (Map.isempty () && size! = 0)) {throw new IllegalStateException (GetClass (). GetName () + ". SizeOf () is Repor                Ting inconsistent 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 the number of automatic removal data            (Number of times)} Entryremoved (True, key, value, NULL);//used to notify that the data has been removed if you need to know a dataWhen to be removed you need to write this method from entryremoved}} 
The above source code I gave the explanation, very good understanding. It is important to note that the TrimToSize method is public, which means that we can actually invoke this method. This is very significant. Remember him, you'll use it.

The following question is: 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 way to add a new data to LRUCache put inside, and in the way through get (K key) This method to obtain a data, etc. Will call TrimToSize to detect it once. Let's look at the put inside how to call:

    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);            Previous = Map.put (key, value);            if (previous! = null) {                Size-= safesizeof (key, previous);}        }        if (previous! = NULL) {//Add duplicate position data, remove old data            entryremoved (False, key, previous, value);        }        TrimToSize (maxSize);//detect if the cached data is full        return previous;    }

(4)Careful people in the above source can be found that the original operation of the LRUCache have been added synchronized to ensure thread safety, yes, LRUCache is thread-safe, and other methods are used to synchronized

(5) In fact, you should have a question immediately: if LRUCache has deleted a data, but now call LRUCache's Get method to get this data? To see if the source code solves this problem:

    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++;//into the number of times the data was obtained return mapvalue;//successfully obtained this data } misscount++;//the number of data failures}/* Attempt to create a value. This is a long time, and the map * May is different when create () returns.  If a conflicting value is * added to the map while create () is working, we leave that value in * the map         and release the created value.        */V Createdvalue = Create (key);//Attempt to create this data if (Createdvalue = = null) {return null;//failed to create data } synchronized (this) {///Join this re-created data createcount++;//new data creation Number Mapvalue = Map.put (Key, creat            Edvalue); if (mapvalue! = null) {//There is a conflict so undo the last put Map.put (key, Mapvalue);            } else {size + safesizeof (key, Createdvalue);            }} if (Mapvalue! = null) {entryremoved (False, Key, Createdvalue, Mapvalue);        return mapvalue;        } else {trimtosize (maxSize);//Check if full return createdvalue; }    }
As you can see from the above analysis, we can recreate data that does not already exist from the write create method. This method defaults to doing nothing, so you need to do it yourself

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


Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Android LRUCache Source parsing

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.