@946898963
2018-05-18T12:16:40.000000Z
字数 3301
阅读 1390
Android控件跟框架
Android源码分析
Volley在对响应的实体进行操作的时候,使用到了byte[],由于volley是轻量级频次高的网络请求框架,因此会大量使用到byte[],这样的话会频繁创建和销毁byte[]。为了提高性能,volley定义了一个byte[]缓冲池,即ByteArrayPool。
更详细的说,由于Volley的目的是同时出现高并发的请求,并且很快结束。如果通过普通的方式一次性创建大量的请求对象,然后等待GC,有可能造成内存抖动.Volley认为权衡的方法是使用固定大小的内存,专门用于创建请求,虽然提高了内存占用,但这种占用是持久的,不会引起重复的占用,也不会引起大量的GC占用时间,所以创建了ByteArrayPool专门用于此目的。
默认使用容量为4K的ByteArrayPool作为请求内存空间。
在ByteArrayPool 内,定义了两个集合,分别是存储按大小顺序排列byte[]的list和按使用先后顺序排列byte[]的list。在volley中所需要使用到的byte[]从该缓冲池中来取,当byte[]使用完毕后再归还到该缓冲池,从而避免频繁的创建和销毁byte[],在缓存池满了的时候删除该集合中的最前面元素,直到缓存池有空闲为止。。
/**
* 字节数组缓冲池:
*
* byte[] 的回收池,用于 byte[] 的回收再利用,减少了内存的分配和回收。主要通过一个元素长度从小到大排序的ArrayList作为 byte[] 的缓存,另有一个按使用时间先后排序的ArrayList属性用于缓存满时清理元素。
*/
public class ByteArrayPool {
/** The buffer pool, arranged by last use 按使用的先后时间顺序排序*/
private List<byte[]> mBuffersByLastUse = new LinkedList<byte[]>();
/** The buffer pool, arranged by buffer size 按大小顺序排序*/
private List<byte[]> mBuffersBySize = new ArrayList<byte[]>(64);
/** The total size of the buffers in the pool 池中所有byte[]的长度之和 */
private int mCurrentSize = 0;
/**
* 池中单个byte[]的最大长度
* The maximum aggregate size of the buffers in the pool. Old buffers are discarded to stay
* under this limit.
*/
private final int mSizeLimit;
/** Compares buffers by size 比较器,用于排序,按byte[]的字节长度进行排序*/
protected static final Comparator<byte[]> BUF_COMPARATOR = new Comparator<byte[]>() {
@Override
public int compare(byte[] lhs, byte[] rhs) {
return lhs.length - rhs.length;
}
};
/**
* 创建byte[]缓冲池,并设定池中单个byte[]的最大长度
* @param sizeLimit the maximum size of the pool, in bytes
*/
public ByteArrayPool(int sizeLimit) {
mSizeLimit = sizeLimit;
}
/**
* 从池中获取一个可用的byte[],如果没有,就创建一个。参数为想要获取多大长度的byte[]
* Returns a buffer from the pool if one is available in the requested size, or allocates a new
* one if a pooled one is not available.
*
* @param len the minimum size, in bytes, of the requested buffer. The returned buffer may be
* larger.
* @return a byte[] buffer is always returned.
*/
public synchronized byte[] getBuf(int len) {
//遍历按长度排序的池
for (int i = 0; i < mBuffersBySize.size(); i++) {
byte[] buf = mBuffersBySize.get(i);
//如果当前的byte[]的长度大于给定的长度,就返回该byte[]
if (buf.length >= len) {
//池中所有byte[]的长度之和减去返回出去的byte[]的长度
mCurrentSize -= buf.length;
//从按顺序排列的池中移除该byte[]
mBuffersBySize.remove(i);
//从按使用顺序排列的池中移除该byte[]表示该byte[]正在使用中,其他不能再使用该byte[]
mBuffersByLastUse.remove(buf);
return buf;
}
}
//创建一个新的byte[]
return new byte[len];
}
/**
* Returns a buffer to the pool, throwing away old buffers if the pool would exceed its allotted
* size.
* 当使用完一个byte[]后,将该byte[]返回到池中
* @param buf the buffer to return to the pool.
*/
public synchronized void returnBuf(byte[] buf) {
//如果为空或者超过了设定的单个byte[]的最大长度 那么就不再池中保存该byte[]
if (buf == null || buf.length > mSizeLimit) {
return;
}
//在按使用时间顺序排序的池中添加该byte[]
mBuffersByLastUse.add(buf);
//利用二分查找法,找出在按大小排序的池中该byte[]应该存放的位置
int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR);
//如果找不到,则返回-1
if (pos < 0) {
//当找不到时,也就是在0位置添加
pos = -pos - 1;
}
mBuffersBySize.add(pos, buf);
//增加最大长度
mCurrentSize += buf.length;
//清理,不能超过字节总数最大值
trim();
}
/**
* Removes buffers from the pool until it is under its size limit.
*/
private synchronized void trim() {
//当现有字节总数超过了设定的界限,那么需要清理
while (mCurrentSize > mSizeLimit) {
//按照使用的先后顺序来倾全力,最新使用的最先被清除
byte[] buf = mBuffersByLastUse.remove(0);
//同样在该池中也清除
mBuffersBySize.remove(buf);
//减小现有字节最大长度
mCurrentSize -= buf.length;
}
}
}
其实其主要思路就是:将最新使用的放在mBuffersByLastUse的最后面,这样回收的就最晚。而且LruCache的实现思路也和这个完全一样,建议阅读LruCache源码解析。
参考链接:
Android中的volley_5_字节数组缓冲池ByteArrayPool 和使用缓冲池技术的自定义的PoolingByteArrayOutputStream
Volley之ByteArrayPool——LruCache实现
vooley源码之ByteArrayPool