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