1d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru/* 2d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Copyright (C) 2012 The Android Open Source Project 3d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 4d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Licensed under the Apache License, Version 2.0 (the "License"); 5d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * you may not use this file except in compliance with the License. 6d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * You may obtain a copy of the License at 7d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 8d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * http://www.apache.org/licenses/LICENSE-2.0 9d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 10d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Unless required by applicable law or agreed to in writing, software 11d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * distributed under the License is distributed on an "AS IS" BASIS, 12d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * See the License for the specific language governing permissions and 14d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * limitations under the License. 15d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 16d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 17d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Querupackage com.android.volley.toolbox; 18d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 19d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.ArrayList; 20d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Collections; 21d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.Comparator; 22d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.LinkedList; 23d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queruimport java.util.List; 24d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 25d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru/** 26d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * ByteArrayPool is a source and repository of <code>byte[]</code> objects. Its purpose is to 27d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * supply those buffers to consumers who need to use them for a short period of time and then 28d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * dispose of them. Simply creating and disposing such buffers in the conventional manner can 29d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * considerable heap churn and garbage collection delays on Android, which lacks good management of 30d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * short-lived heap objects. It may be advantageous to trade off some memory in the form of a 31d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * permanently allocated pool of buffers in order to gain heap performance improvements; that is 32d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * what this class does. 33d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <p> 34d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * A good candidate user for this class is something like an I/O system that uses large temporary 35d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <code>byte[]</code> buffers to copy data around. In these use cases, often the consumer wants 36d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * the buffer to be a certain minimum size to ensure good performance (e.g. when copying data chunks 37d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * off of a stream), but doesn't mind if the buffer is larger than the minimum. Taking this into 38d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * account and also to maximize the odds of being able to reuse a recycled buffer, this class is 39d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * free to return buffers larger than the requested size. The caller needs to be able to gracefully 40d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * deal with getting buffers any size over the minimum. 41d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <p> 42d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * If there is not a suitably-sized buffer in its recycling pool when a buffer is requested, this 43d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * class will allocate a new buffer and return it. 44d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <p> 45d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * This class has no special ownership of buffers it creates; the caller is free to take a buffer 46d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * it receives from this pool, use it permanently, and never return it to the pool; additionally, 47d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * it is not harmful to return to this pool a buffer that was allocated elsewhere, provided there 48d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * are no other lingering references to it. 49d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * <p> 50d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * This class ensures that the total size of the buffers in its recycling pool never exceeds a 51d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * certain byte limit. When a buffer is returned that would cause the pool to exceed the limit, 52d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * least-recently-used buffers are disposed. 53d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 54d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Querupublic class ByteArrayPool { 55d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** The buffer pool, arranged both by last use and by buffer size */ 56d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private List<byte[]> mBuffersByLastUse = new LinkedList<byte[]>(); 57d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private List<byte[]> mBuffersBySize = new ArrayList<byte[]>(64); 58d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 59d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** The total size of the buffers in the pool */ 60d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private int mCurrentSize = 0; 61d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 62d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 63d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * The maximum aggregate size of the buffers in the pool. Old buffers are discarded to stay 64d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * under this limit. 65d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 66d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private final int mSizeLimit; 67d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 68d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** Compares buffers by size */ 69d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru protected static final Comparator<byte[]> BUF_COMPARATOR = new Comparator<byte[]>() { 70d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru @Override 71d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public int compare(byte[] lhs, byte[] rhs) { 72d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru return lhs.length - rhs.length; 73d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 74d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru }; 75d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 76d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 77d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param sizeLimit the maximum size of the pool, in bytes 78d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 79d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public ByteArrayPool(int sizeLimit) { 80d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mSizeLimit = sizeLimit; 81d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 82d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 83d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 84d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Returns a buffer from the pool if one is available in the requested size, or allocates a new 85d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * one if a pooled one is not available. 86d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 87d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param len the minimum size, in bytes, of the requested buffer. The returned buffer may be 88d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * larger. 89d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @return a byte[] buffer is always returned. 90d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 91d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public synchronized byte[] getBuf(int len) { 92d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru for (int i = 0; i < mBuffersBySize.size(); i++) { 93d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru byte[] buf = mBuffersBySize.get(i); 94d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (buf.length >= len) { 95d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mCurrentSize -= buf.length; 96d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mBuffersBySize.remove(i); 97d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mBuffersByLastUse.remove(buf); 98d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru return buf; 99d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 100d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 101d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru return new byte[len]; 102d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 103d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 104d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 105d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Returns a buffer to the pool, throwing away old buffers if the pool would exceed its allotted 106d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * size. 107d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * 108d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * @param buf the buffer to return to the pool. 109d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 110d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru public synchronized void returnBuf(byte[] buf) { 111d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (buf == null || buf.length > mSizeLimit) { 112d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru return; 113d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 114d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mBuffersByLastUse.add(buf); 115d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR); 116d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru if (pos < 0) { 117d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru pos = -pos - 1; 118d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 119d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mBuffersBySize.add(pos, buf); 120d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mCurrentSize += buf.length; 121d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru trim(); 122d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 123d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 124d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru /** 125d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru * Removes buffers from the pool until it is under its size limit. 126d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru */ 127d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru private synchronized void trim() { 128d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru while (mCurrentSize > mSizeLimit) { 129d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru byte[] buf = mBuffersByLastUse.remove(0); 130d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mBuffersBySize.remove(buf); 131d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru mCurrentSize -= buf.length; 132d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 133d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru } 134d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru 135d56b88ae161057e848e7410d1b9ce5b0b8c427fcJean-Baptiste Queru} 136