Volley之ByteArrayPool——LruCache实现
来源:互联网 发布:淘宝网店铺排名 编辑:程序博客网 时间:2024/05/29 15:32
基础
其主要作用是byte[]的缓存池,可以指定最大的缓存的byte数目。当缓存的byte数目超过指定的最大值时,以LRU策略进行回收。在频繁进行I/O操作时,如果不停地创建byte[],会导致堆内存的极速消耗,因为gc的回收并不是太及时。
原理
用一个有序集合存储缓存的byte[],用另一个集合存储待删的byte[]——在缓存池满了的时候删除该集合中的最前面元素,直到缓存池有空闲为止。
源码及注释
import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.LinkedList;import java.util.List;/** * byte[]的缓存池,可以指定最大的缓存的byte数目。当缓存的byte数目超过指定的最大值时,以LRU策略进行回收。 * 用一个集合记录该byte[]的使用顺序,使用另一个集合记录已经使用过的byte[],保证对byte[]的重复利用。 */public class ByteArrayPool { /** * byte[]待删集合,记录了byte[]的使用顺序。当缓存的byte数目超过指定的最大值时,会回收该list集合中的第一个元素。 * 每一次从变量mBuffersBySize中获取到合适的byte[]时,会将返回值从该集合中删除,因为这个byte[]是最近使用的。 * 每一次回收该集合中第0个元素,保证了回收的byte[]是使用时间最久远的。 */ private List<byte[]> mBuffersByLastUse = new LinkedList<>(); /** * byte[]的真正缓存list集合。每一次获取时都是从该集合中获取或者新生成 */ private List<byte[]> mBuffersBySize = new ArrayList<>(64); /** * 当前缓存池中已经有byte数 */ private int mCurrentSize = 0; /** * 本缓存池中最大的缓存byte数 */ private final int mSizeLimit; /** * 哪个byte数组元素少,哪个在前 */ protected static final Comparator<byte[]> BUF_COMPARATOR = new Comparator<byte[]>() { @Override public int compare(byte[] lhs, byte[] rhs) { return lhs.length - rhs.length; } }; public ByteArrayPool(int sizeLimit) { mSizeLimit = sizeLimit; } /** * @param len.返回的byte[]的最小长度,有可能返回的byte[]的长度大于该len */ public synchronized byte[] getBuf(int len) { for (int i = 0; i < mBuffersBySize.size(); i++) { byte[] buf = mBuffersBySize.get(i); if (buf.length >= len) { mCurrentSize -= buf.length;//返回后,将当前缓存池中缓存的byte数目减少 mBuffersBySize.remove(i);//删掉,保证了一个byte[]数组不会提供给两个客户端使用 //本次使用了该缓存,所以将其从待删集合中删除,这样即使缓存的byte数量超过最大的范围,也不会被删掉。保证了最新的不会被删。 //同时,当一个byte[]被多次使用时,则该byte[]会被存储到该集合的最后端,也不会被立即回收 mBuffersByLastUse.remove(buf); return buf; } } return new byte[len];//没有合适的或者第一次会直接返回 } /** * 将使用过的byte数组返回到缓存池中 */ public synchronized void returnBuf(byte[] buf) { if (buf == null || buf.length > mSizeLimit) { return; } mBuffersByLastUse.add(buf);//待删集合,不能对回收的byte[]进行排序 //该二分查找的返回值有两个效果:其一知道查找的有木有,其二如果木有,插入时插入的位置。 int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR); if (pos < 0) { pos = -pos - 1; } mBuffersBySize.add(pos, buf); mCurrentSize += buf.length; trim(); } /** * 回收该回收的部分。 */ private synchronized void trim() { while (mCurrentSize > mSizeLimit) { byte[] buf = mBuffersByLastUse.remove(0); mBuffersBySize.remove(buf); mCurrentSize -= buf.length; } }}
主要思路都在注释中。其实其主要思路就是:将最新使用的放在mBuffersByLastUse的最后面,这样回收的就最晚。而且LruCache的实现思路也和这个完全一样。
LruCache
import java.util.LinkedHashMap;import java.util.Map;public class LruCache<K, V> { private final LinkedHashMap<K, V> map;//使用LinkedHashMap的主要原因在于:它的put的顺序与迭代器的取的顺序一致。 /** 最大的缓存数*/ private int size; private int maxSize; private int putCount; private int createCount; private int evictionCount; private int hitCount; private int missCount; 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); } /** * 重新定义最大的缓存大小 */ public void resize(int maxSize) { if (maxSize <= 0) { throw new IllegalArgumentException("maxSize <= 0"); } synchronized (this) { this.maxSize = maxSize; } trimToSize(maxSize); } 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++; } /* * 通过key值获取value值。如果该key值对应的有value了,则放弃create()返回的值。 * 因为create()可能耗费的时间比较长,所以create()执行完毕后,key可能对应的有value。 */ V createdValue = create(key); if (createdValue == null) { return null; } synchronized (this) { createCount++; mapValue = map.put(key, createdValue); if (mapValue != null) { // key值有冲突,放弃create()生成的value map.put(key, mapValue); } else { size += safeSizeOf(key, createdValue); } } if (mapValue != null) { entryRemoved(false, key, createdValue, mapValue); return mapValue; } else { trimToSize(maxSize); return createdValue; } } /** * 这里是先将数据加入缓存中,再判断缓存的大小是否超过了限制。 * 这会导致在临界状态下依旧会OOM,可以先移除多余的部分,再将新的加入到缓存中。 */ 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++; size += safeSizeOf(key, value); previous = map.put(key, value);//返回key对应的value。 if (previous != null) { size -= safeSizeOf(key, previous);//previous是要被删除的,所以size应减除previous的大小 } } if (previous != null) { entryRemoved(false, key, previous, value); } trimToSize(maxSize); return previous; } /** * 移除存在时间最久的对象,直到缓存的大小不大于最大缓存范围 * 整理整个缓存池,防止超出最大的范围 */ 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; }//因为获取的顺序与存储的顺序一致,所以该句得到的就是存在时间最久的缓存对象。 Map.Entry<K, V> toEvict = map.entrySet().iterator().next(); key = toEvict.getKey(); value = toEvict.getValue(); map.remove(key); size -= safeSizeOf(key, value); evictionCount++; } entryRemoved(true, key, value, null); } } public final V remove(K key) { if (key == null) { throw new NullPointerException("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; } /** * oldValue从缓存池中移除时的回调 */ protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {} /** * 根据key值生成value。 */ protected V create(K key) { return null; }/** * 对sizeOf()的大小加一层判断而已 */ private int safeSizeOf(K key, V value) { int result = sizeOf(key, value); if (result < 0) { throw new IllegalStateException("Negative size: " + key + "=" + value); } return result; } /** * 获取对应value的大小。一般都需要重写该方法 */ protected int sizeOf(K key, V value) { return 1; } /** * trimToSize()传入-1,则所有的缓存对象都会被清除 */ public final void evictAll() { trimToSize(-1); // -1 will evict 0-sized elements } //剩余代码无意义,略}
0 0
- Volley之ByteArrayPool——LruCache实现
- Volley ByteArrayPool
- vooley源码之ByteArrayPool
- volley+Lrucache+DiskLruCahe实现的三级缓存
- Volley网络请求封装之LruCache源码分析
- leveldb源码解析6——Cache之LRUCache实现详解
- 安卓开发——关于图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- 安卓开发笔记——关于图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- 安卓开发——关于图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- 安卓开发笔记——关于图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- Bitmap——内存缓存LruCache实现原理
- LruCache实现
- Android Volley框架的使用之图片的三级缓存策略(内存LruCache+磁盘DiskLruCache+网络Volley)
- Volley源码学习(二):网络请求处理,HurlStack类,BasicNetwork类,ByteArrayPool,PoolingByteArrayOutputStream
- 源码解析 ——LRUCache
- ListView显示图片(Volley+ImageRequest+LruCache+DiskCache)
- Volley源码解析——从实现角度深入剖析volley
- LRUCache算法实现
- 启用不安全的HTTP方法解决方案
- javaweb学习总结(十一)——使用Cookie进行会话管理
- android Camera 如何判断当前使用的摄像头是前置还是后置
- leetcode 74 Search a 2D Matrixf
- Linux中 `pkg-config` 命令的使用
- Volley之ByteArrayPool——LruCache实现
- HibernateTemplate空指针?
- jQuery选择器总结
- AngularJS Select(选择框)
- Communications link failure的解决办法
- 列表用处大!代码优化!
- 7.26
- Android 一键清理、内存清理功能实现
- UITableView性能检测相关