-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added first iteration of fix for #18, Added pooling byte array for de…
…coding inputstream, Updated sampling impl
- Loading branch information
Showing
4 changed files
with
257 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
135 changes: 135 additions & 0 deletions
135
library/src/com/handlerexploit/common/utils/ByteArrayPool.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
/* | ||
* 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.handlerexploit.common.utils; | ||
|
||
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[]>() { | ||
@Override | ||
public 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; | ||
} | ||
} | ||
|
||
} |
61 changes: 61 additions & 0 deletions
61
library/src/com/handlerexploit/common/utils/PoolingBufferedInputStream.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package com.handlerexploit.common.utils; | ||
|
||
import java.io.BufferedInputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
|
||
public class PoolingBufferedInputStream extends BufferedInputStream { | ||
|
||
private static final int DEFAULT_SIZE = 256; | ||
|
||
private final ByteArrayPool mPool; | ||
|
||
public PoolingBufferedInputStream(InputStream in, ByteArrayPool pool) { | ||
this(in, pool, DEFAULT_SIZE); | ||
} | ||
|
||
public PoolingBufferedInputStream(InputStream in, ByteArrayPool pool, int size) { | ||
super(in, 1); | ||
mPool = pool; | ||
buf = mPool.getBuf(Math.max(size, DEFAULT_SIZE)); | ||
} | ||
|
||
@Override | ||
public void close() throws IOException { | ||
mPool.returnBuf(buf); | ||
buf = null; | ||
super.close(); | ||
} | ||
|
||
@Override | ||
public void finalize() { | ||
mPool.returnBuf(buf); | ||
} | ||
|
||
/** | ||
* Ensures there is enough space in the buffer for the given number of | ||
* additional bytes. | ||
*/ | ||
private void expand(int i) { | ||
/* Can the buffer handle @i more bytes, if not expand it */ | ||
if (count + i <= buf.length) { | ||
return; | ||
} | ||
byte[] newbuf = mPool.getBuf((count + i) * 2); | ||
System.arraycopy(buf, 0, newbuf, 0, count); | ||
mPool.returnBuf(buf); | ||
buf = newbuf; | ||
} | ||
|
||
@Override | ||
public synchronized int read(byte[] buffer, int offset, int len) throws IOException { | ||
expand(len); | ||
return super.read(buffer, offset, len); | ||
} | ||
|
||
@Override | ||
public synchronized int read() throws IOException { | ||
expand(1); | ||
return super.read(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters