原理:
当需要使用byte[]的时候从缓冲池中获取,如果没有合适的大小,则根据指定大小创建一个新的byte[],使用完成后可在mSizeLimit的限制下缓存到缓冲池中;
目的:
我们知道在gc的过程中可能会阻塞主线程,因此尽量避免产生大量的堆信息从而减少gc操作,对我们app的性能改善是很有帮助的;那么使用缓冲池的目的是为了解决在byte[]的创建中产生大量的堆信息以及在gc过程中的延迟,从而改善app的性能;
使用场景:
一些I/O操作,比如网络操作,每次数据的解析将会产生大量的不同大小的byte[]对象,如果能够某个范围类将使用的过的byte[]对象缓存起来,方便以后使用,那么对app性能的提升有很大的改善;
源码分析:
ByteArrayPool类中关键字段:mBuffersByLastUse、mBuffersBySize、mCurrentSize、mSizeLimit;根据字面意思就能够理解,这里就不在多说;
首先看获得buffer的方法,getBuf(int len);根据指定的大小从缓冲池中获得buffer(该buffer可能比指定的len要大),否则创建一个新的buffer;
/**
* 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);
if (buf.length >= len) {
mCurrentSize -= buf.length;
mBuffersBySize.remove(i);
mBuffersByLastUse.remove(buf);
return buf;
}
}
return new byte[len];
}
buffer使用完成后缓存到该缓冲池中,方法为returnBuf(byte[] buf);如果buf大于mSizeLimit则不缓存,否则将buf放入mBuffersByLastUse中,然后根据Collections.binarySearch()查找在mBuffersBySize的位置,并添加到mBuffersBySize中,再调用trim()方法:
/**
* Returns a buffer to the pool, throwing away old buffers if the pool would exceed its allotted
* size.
*
* @param buf the buffer to return to the pool.
*/
public synchronized void returnBuf(byte[] buf) {
if (buf == null || buf.length > mSizeLimit) {
return;
}
mBuffersByLastUse.add(buf);
int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR);
if (pos < 0) {
pos = -pos - 1;
}
mBuffersBySize.add(pos, buf);
mCurrentSize += buf.length;
trim();
}
trim()方法的作用:如果mCurrentSize 大于mSizeLimit,则从mBuffersByLastUse和mBuffersBySize中移除部分buffer,直到mCurrentSize 在mSizeLimit限制范围内;
/**
* 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;
}
}
该类的使用主要结合了PoolingByteArrayOutputStream类,在Volley中体现在BasicNetwork的entityToBytes(HttpEntity entity)方法中,代码如下:
/** Reads the contents of HttpEntity into a byte[]. */
private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError {
PoolingByteArrayOutputStream bytes =
new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength());
byte[] buffer = null;
try {
InputStream in = entity.getContent();
if (in == null) {
throw new ServerError();
}
buffer = mPool.getBuf(1024);
int count;
while ((count = in.read(buffer)) != -1) {
bytes.write(buffer, 0, count);
}
return bytes.toByteArray();
} finally {
try {
// Close the InputStream and release the resources by "consuming the content".
entity.consumeContent();
} catch (IOException e) {
// This can happen if there was an exception above that left the entity in
// an invalid state.
VolleyLog.v("Error occured when calling consumingContent");
}
mPool.returnBuf(buffer);
bytes.close();
}
}
总结:
在我们app的开发中为什么推荐使用volley呢?就是因为volley在一些细节上做得比较好,考虑得比较周全,对我们的app的性能提升有一定的帮助;
现在做Android app开发很多人都觉得比较简单,用一些开源的工具进行组合就能够将我们的app开发出来,但是如果需要做一个精细化高性能的app还是需要技术含量的,需要对底层及原理有一定的了解。希望大家在app的开发过程中做一定的性能优化,提升app的流畅度,提供更好的用户体验。