Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

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