通过LruCache防止Android OOM
程序员文章站
2022-03-28 17:53:43
LruCache位于android.util.LruCache,用来保证固定长度的Map缓存,如果缓存满了的话,会移除掉最早访问的key-value。在Android中,Bitmap是很占内存的,所以可以考虑使用LruCache。用法如下:private static LruCache mCache;static { mCache = new LruCache(CACHE_MAX_SIZE) {...
LruCache位于android.util.LruCache,用来保证固定长度的Map缓存,如果缓存满了的话,会移除掉最早访问的key-value。在Android中,Bitmap是很占内存的,所以可以考虑使用LruCache。用法如下:
private static LruCache<String, Bitmap> mCache;
static { mCache = new LruCache<String, Bitmap>(CACHE_MAX_SIZE) { @Override protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) { if (oldValue != newValue)//连续put相同key的情况,这种情况也可能导致Bitmap一直增加,所以要把旧的bitmap回收 oldValue.recycle(); } }; }
我们来看一下LruCache的源码。
public void resize(int maxSize) { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } synchronized (this) { //这里考虑了线程安全 this.maxSize = maxSize; } trimToSize(maxSize);//裁剪到指定大小 }
private 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) { break; } // BEGIN LAYOUTLIB CHANGE // get the last item in the linked list. // This is not efficient, the goal here is to minimize the changes // compared to the platform version. Map.Entry<K, V> toEvict = null;//要逐出的实体 for (Map.Entry<K, V> entry : map.entrySet()) { toEvict = entry; } // END LAYOUTLIB CHANGE if (toEvict == null) { break; } key = toEvict.getKey(); value = toEvict.getValue(); map.remove(key); size -= safeSizeOf(key, value); evictionCount++; } entryRemoved(true, key, value, null); } }
/** * Called after a cache miss to compute a value for the corresponding key. * Returns the computed value or null if no value can be computed. The * default implementation returns null. * * <p>The method is called without synchronization: other threads may * access the cache while this method is executing. * * <p>If a value for {@code key} exists in the cache when this method * returns, the created value will be released with {@link #entryRemoved} * and discarded. This can occur when multiple threads request the same key * at the same time (causing multiple values to be created), or when one * thread calls {@link #put} while another is creating a value for the same * key. */ protected V create(K key) { return null; }
这个方法不是线程安全的,在没有通过key拿到value时,会默认创建一个null返回,你也可以通过继承重写create()方法,计算key的默认value。
/** * @param maxSize for caches that do not override {@link #sizeOf}, this is * the maximum number of entries in the cache. For all other caches, * this is the maximum sum of the sizes of the entries in this cache. */ 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);//第三个参数为accessOrder,true代表按key的访问顺序排序,false代表按key的插入顺序排序 }
由于它内部使用了一个LinkedHashMap,给定了accessOrder一个true,所以最早的key-value会在缓存满后被移除。其他put和get都是基于LinkedHashMap的,增加了几个变量的保存,下面我们看下LruCache新增的几个变量。
private int size; //当前存储的大小 private int maxSize; //允许存储的最大缓存数量 private int putCount; //put的次数 private int createCount; //create的次数 private int evictionCount; //逐出的次数 private int hitCount; //通过get取到value的次数 private int missCount; //通过get没有取到value的次数
本文地址:https://blog.csdn.net/a_lwh____/article/details/107379992
上一篇: android handler postDelay源码解析
下一篇: 程序员开始处理遗留代码的时候