LruCache和TreeMap实现数组池复用
内存抖动—>频繁的创建对象和销毁会导致程序一直gc会导致卡顿,严重可能会导致OOM
当处理 int[] byte[] 数组时,可以创建对象数组池来进行对象的复用(减少对象的创建),降低内存抖动,提高性能。
LruCache
LruCache是一个缓存池,里面封装了LinkHashMap和一个双向链表。可以参考Glide的复用机制。
来进行数组的复用。
// An highlighted block
public class ArrayPool3 implements ArrayPool {
private static final String TAG = "ArrayPool";
public static final int ARRAY_POOL_SIZE_BYTES = 4 * 1024 * 1024;
private int maxSize;
private LruCache<Integer, byte[]> cache;
//key 为byte数组长度,value为个数
private final NavigableMap<Integer, Integer> sortedSizes = new TreeMap<>();
public ArrayPool3() {
this(ARRAY_POOL_SIZE_BYTES);
}
public ArrayPool3(int maxSize) {
this.maxSize = maxSize;
this.cache = new LruCache<Integer, byte[]>(maxSize) {
protected int sizeOf(Integer key, byte[] value) {
return value.length;
}
};
}
@Override
public synchronized byte[] get(int len) {
//获得等于或大于比len大的key
Integer key = sortedSizes.ceilingKey(len);
if (key != null) {
byte[] bytes = cache.remove(key);
//计数器 -1
Integer current = sortedSizes.get(key);
if (current == 1) {
sortedSizes.remove(key);
} else {
sortedSizes.put(key, current - 1);
}
return bytes;
}
return new byte[len];
}
@Override
public synchronized void put(byte[] data) {
if (data == null || data.length == 0 || data.length > maxSize) return;
int length = data.length;
Integer current = sortedSizes.get(length);
//计数器+1
sortedSizes.put(length, current == null ? 1 : current + 1);
cache.put(length, data);
}
}
通过LruCache<Integer,(数组)>来进行记录 key值记录了数组的长度,value则是数组。
通过remove方法从cache中取值,通过put向cache中添加(数组使用完后调用put方法)
这样可以完成数组的复用,但是每次的length都是固定的,多大的length只能从池子中获取多大的数组(仅适用于数组大小固定)
通过TreeMap来记录所需数组的长度----->实现数组不同长度的复用
TreeMap底层的实现是红黑树,可以将key有序的排列(HashMap不可以)
private final NavigableMap<Integer, Integer> sortedSizes = new TreeMap<>();
把数组的长度 length 存入到TreeMap的key中,value则存放 大小为 key 的数组剩余个数。
在取值时通过 ceilingKey 可以拿到 大小 >= 所需长度length的 TreeMap的 Key
再通过拿到的 TreeMap的 key 去 cache中获取 数组,,获取到数组后将TreeMap的key对应的value减一
put时----->同样将 数组 存入 cache缓存中, 同时将 TreeMap的对应key的value值 +1