@946898963
2018-05-18T04:16:40.000000Z
字数 3301
阅读 1663
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[]>() {@Overridepublic 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);//如果找不到,则返回-1if (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