Blame | Last modification | View Log | RSS feed
/** Copyright (C) 2012 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.android.volley.toolbox;import java.util.ArrayList;import java.util.Collections;import java.util.Comparator;import java.util.LinkedList;import java.util.List;/*** ByteArrayPool is a source and repository of <code>byte[]</code> objects. Its purpose is to* supply those buffers to consumers who need to use them for a short period of time and then* dispose of them. Simply creating and disposing such buffers in the conventional manner can* considerable heap churn and garbage collection delays on Android, which lacks good management of* short-lived heap objects. It may be advantageous to trade off some memory in the form of a* permanently allocated pool of buffers in order to gain heap performance improvements; that is* what this class does.* <p>* A good candidate user for this class is something like an I/O system that uses large temporary* <code>byte[]</code> buffers to copy data around. In these use cases, often the consumer wants* the buffer to be a certain minimum size to ensure good performance (e.g. when copying data chunks* off of a stream), but doesn't mind if the buffer is larger than the minimum. Taking this into* account and also to maximize the odds of being able to reuse a recycled buffer, this class is* free to return buffers larger than the requested size. The caller needs to be able to gracefully* deal with getting buffers any size over the minimum.* <p>* If there is not a suitably-sized buffer in its recycling pool when a buffer is requested, this* class will allocate a new buffer and return it.* <p>* This class has no special ownership of buffers it creates; the caller is free to take a buffer* it receives from this pool, use it permanently, and never return it to the pool; additionally,* it is not harmful to return to this pool a buffer that was allocated elsewhere, provided there* are no other lingering references to it.* <p>* This class ensures that the total size of the buffers in its recycling pool never exceeds a* certain byte limit. When a buffer is returned that would cause the pool to exceed the limit,* least-recently-used buffers are disposed.*/public class ByteArrayPool {/** The buffer pool, arranged both by last use and by buffer size */private List<byte[]> mBuffersByLastUse = new LinkedList<byte[]>();private List<byte[]> mBuffersBySize = new ArrayList<byte[]>(64);/** The total size of the buffers in the pool */private int mCurrentSize = 0;/*** 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 */protected static final Comparator<byte[]> BUF_COMPARATOR = new Comparator<byte[]>() {@Overridepublic int compare(byte[] lhs, byte[] rhs) {return lhs.length - rhs.length;}};/*** @param sizeLimit the maximum size of the pool, in bytes*/public ByteArrayPool(int sizeLimit) {mSizeLimit = sizeLimit;}/*** 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];}/*** 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();}/*** 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;}}}