1d5bf0ecf31f33fb31763995e3c8bfab69dc2457fWei-Ta Chen/* 258b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * Copyright (C) 2012 The Android Open Source Project 358b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * 458b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * Licensed under the Apache License, Version 2.0 (the "License"); 558b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * you may not use this file except in compliance with the License. 658b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * You may obtain a copy of the License at 7d5bf0ecf31f33fb31763995e3c8bfab69dc2457fWei-Ta Chen * 858b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * http://www.apache.org/licenses/LICENSE-2.0 958b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * 1058b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * Unless required by applicable law or agreed to in writing, software 1158b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * distributed under the License is distributed on an "AS IS" BASIS, 1258b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1358b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * See the License for the specific language governing permissions and 146699e7ea2e981dccc2f3c41b5dcf1c860b11558dJean-Baptiste Queru * limitations under the License. 15a8dbe3f21c692b274486d03e7e44b4d19a0ea06bSkia_Android Canary Bot */ 16a8dbe3f21c692b274486d03e7e44b4d19a0ea06bSkia_Android Canary Bot 17a8dbe3f21c692b274486d03e7e44b4d19a0ea06bSkia_Android Canary Botpackage com.android.volley.toolbox; 1858b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot 1958b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Botimport java.util.ArrayList; 2058b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Botimport java.util.Collections; 2158b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Botimport java.util.Comparator; 2258b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Botimport java.util.LinkedList; 2358b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Botimport java.util.List; 2458b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot 2558b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot/** 2658b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * ByteArrayPool is a source and repository of <code>byte[]</code> objects. Its purpose is to 2758b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * supply those buffers to consumers who need to use them for a short period of time and then 2858b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * dispose of them. Simply creating and disposing such buffers in the conventional manner can 2958b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * considerable heap churn and garbage collection delays on Android, which lacks good management of 3058b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * short-lived heap objects. It may be advantageous to trade off some memory in the form of a 3158b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * permanently allocated pool of buffers in order to gain heap performance improvements; that is 3258b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * what this class does. 3358b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * <p> 3458b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * A good candidate user for this class is something like an I/O system that uses large temporary 3558b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * <code>byte[]</code> buffers to copy data around. In these use cases, often the consumer wants 3658b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * the buffer to be a certain minimum size to ensure good performance (e.g. when copying data chunks 3758b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * off of a stream), but doesn't mind if the buffer is larger than the minimum. Taking this into 3858b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * account and also to maximize the odds of being able to reuse a recycled buffer, this class is 3958b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * free to return buffers larger than the requested size. The caller needs to be able to gracefully 4058b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * deal with getting buffers any size over the minimum. 4158b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * <p> 4258b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * If there is not a suitably-sized buffer in its recycling pool when a buffer is requested, this 4358b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * class will allocate a new buffer and return it. 4458b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * <p> 4558b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * This class has no special ownership of buffers it creates; the caller is free to take a buffer 4658b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * it receives from this pool, use it permanently, and never return it to the pool; additionally, 4758b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * it is not harmful to return to this pool a buffer that was allocated elsewhere, provided there 4858b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * are no other lingering references to it. 4958b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * <p> 5058b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * This class ensures that the total size of the buffers in its recycling pool never exceeds a 5158b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * certain byte limit. When a buffer is returned that would cause the pool to exceed the limit, 5258b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * least-recently-used buffers are disposed. 5358b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot */ 5458b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Botpublic class ByteArrayPool { 5558b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot /** The buffer pool, arranged both by last use and by buffer size */ 5658b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot private List<byte[]> mBuffersByLastUse = new LinkedList<byte[]>(); 5758b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot private List<byte[]> mBuffersBySize = new ArrayList<byte[]>(64); 5858b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot 5958b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot /** The total size of the buffers in the pool */ 6058b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot private int mCurrentSize = 0; 6158b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot 6258b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot /** 6358b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * The maximum aggregate size of the buffers in the pool. Old buffers are discarded to stay 6458b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * under this limit. 6558b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot */ 6658b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot private final int mSizeLimit; 6758b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot 6858b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot /** Compares buffers by size */ 6958b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot protected static final Comparator<byte[]> BUF_COMPARATOR = new Comparator<byte[]>() { 7058b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot @Override 7158b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot public int compare(byte[] lhs, byte[] rhs) { 7258b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot return lhs.length - rhs.length; 7358b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot } 7458b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot }; 7558b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot 7658b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot /** 7758b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * @param sizeLimit the maximum size of the pool, in bytes 7858b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot */ 7958b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot public ByteArrayPool(int sizeLimit) { 8058b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot mSizeLimit = sizeLimit; 8158b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot } 8258b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot 8358b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot /** 8458b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * Returns a buffer from the pool if one is available in the requested size, or allocates a new 8558b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * one if a pooled one is not available. 8658b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * 8758b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * @param len the minimum size, in bytes, of the requested buffer. The returned buffer may be 8858b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * larger. 8958b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * @return a byte[] buffer is always returned. 9058b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot */ 9158b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot public synchronized byte[] getBuf(int len) { 9258b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot for (int i = 0; i < mBuffersBySize.size(); i++) { 9358b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot byte[] buf = mBuffersBySize.get(i); 9458b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot if (buf.length >= len) { 9558b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot mCurrentSize -= buf.length; 9658b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot mBuffersBySize.remove(i); 9758b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot mBuffersByLastUse.remove(buf); 9858b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot return buf; 9958b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot } 10058b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot } 10158b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot return new byte[len]; 10258b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot } 10358b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot 10458b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot /** 10558b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * Returns a buffer to the pool, throwing away old buffers if the pool would exceed its allotted 10658b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * size. 107f56b9c160fe9eba8bfa1779a4ee54b0082a278b3Skia_Android Canary Bot * 10858b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * @param buf the buffer to return to the pool. 10958b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot */ 11058b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot public synchronized void returnBuf(byte[] buf) { 11158b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot if (buf == null || buf.length > mSizeLimit) { 11258b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot return; 11358b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot } 11458b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot mBuffersByLastUse.add(buf); 11558b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR); 11658b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot if (pos < 0) { 117dd9fdd91285c6e71431bafc11d0d7b5bcabb203fSkia_Android Canary Bot pos = -pos - 1; 11858b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot } 11958b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot mBuffersBySize.add(pos, buf); 12058b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot mCurrentSize += buf.length; 12158b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot trim(); 12258b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot } 12358b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot 12458b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot /** 12558b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot * Removes buffers from the pool until it is under its size limit. 12658b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot */ 12758b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot private synchronized void trim() { 12858b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot while (mCurrentSize > mSizeLimit) { 12958b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot byte[] buf = mBuffersByLastUse.remove(0); 13058b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot mBuffersBySize.remove(buf); 13158b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot mCurrentSize -= buf.length; 13258b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot } 1339e143897ca864c4b577887b26250584ad1e2a75fSkia_Android Canary Bot } 13458b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot 13558b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot} 13658b38c2d473883bbc7f7c8a080560fe117cdfef6Skia_Android Canary Bot