现在大多数的内存缓存都是用这个LRUCache来进行缓存的,算法主要就是 最近最少使用
但是其中的原理,有时候没有稍微深入研究的话,还是停留下会用的程度上(会用还不行了 :)(捂脸)
深入源码之前先简单的使用一下,图片缓存大致就是这样使用的
//获取应用程序的最大可用内存int maxMemory = (int) Runtime.getRuntime().maxMemory();int cacheSize = maxMemory / 8;LruCachelruCache = new LruCache (cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { //这里一定要复写 ,返回的是bitmap的大小 return bitmap.getByteCount(); }};Bitmap bitmap = createBitmap() ;lruCache.put("url1", bitmap);lruCache.put("url2", bitmap);lruCache.put("url3", bitmap);Bitmap bitmap1 = lruCache.get("url1")复制代码
上面就是正常的使用;然后就是查看源码中为什么是会是 最近最少使用的算法
- new 对象需要做的操作
public LruCache(int maxSize) { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } //maxSize就是我们必须传入的大小限制, this.maxSize = maxSize; //注意这里就是使用LinkedHashMap来进行内存缓存的策略 this.map = new LinkedHashMap(0, 0.75f, true);}put复制代码
- put的操作,map的put操作
public final V put(K key, V value) { if (key == null || value == null) { throw new NullPointerException("key == null || value == null"); } V previous; synchronized (this) { putCount++; //这里的safeSizeOf 最后会调用sizeOf方法,如果我们复写这个方法就使用,没有复写就返回 1 size += safeSizeOf(key, value); //这里调用map的put方法,如果previous存在,将这个替换的previous 减去它的大小; previous = map.put(key, value); if (previous != null) { size -= safeSizeOf(key, previous); } } //如果复写这个方法,就会调用,一般不用关心 if (previous != null) { entryRemoved(false, key, previous, value); } //记住下面的方法,就是删除的操作!!!下面会重点介绍 trimToSize(maxSize); return previous;}复制代码
- get操作 , map的get方法
public final V get(K key) { if (key == null) { throw new NullPointerException("key == null"); } V mapValue; synchronized (this) { mapValue = map.get(key); if (mapValue != null) { hitCount++; return mapValue; } missCount++; }}复制代码
- trimToSize操作,这是重点!!!
public void trimToSize(int maxSize) { while (true) { K key; V value; synchronized (this) { if (size < 0 || (map.isEmpty() && size != 0)) { throw new IllegalStateException(getClass().getName() + ".sizeOf() is reporting inconsistent results!"); } if (size <= maxSize || map.isEmpty()) { break; } //如果size > maxSize 就进行删除操作 //这里就是取出map集合的第一个,进行remove,然后再次调用SizeOf更新size。 Map.EntrytoEvict = map.entrySet().iterator().next(); key = toEvict.getKey(); value = toEvict.getValue(); map.remove(key); size -= safeSizeOf(key, value); evictionCount++; } entryRemoved(true, key, value, null); }}复制代码
其实LRUCache源码里看的差不多是对LinkedHashMap的封装!主要还是要去查询LinkedHashMap的源码才能知道为什么trimToSize中的方法里map取迭代器的第一个就是删除最近少使用的那个item了。
- 对于LinkedHashMap的源码分析,,很是详细的!