Use ByteBufUtil.BYTE_ARRAYS ThreadLocal temporary arrays in more places (#8464)

Motivation:

#8388 introduced a reusable ThreadLocal<byte[]> for use in
decodeString(...). It can be used in more places in the buffer package
to avoid temporary allocations of small arrays.

Modifications:

Encapsulate use of the ThreadLocal in a static package-private
ByteBufUtil.threadLocalTempArray(int) method, and make use of it from a
handful of new places including ByteBufUtil.readBytes(...).

Result:

Fewer short-lived small byte array allocations.
This commit is contained in:
Nick Hill 2018-11-05 12:11:28 -08:00 committed by Norman Maurer
parent 10539f4dc7
commit 5954110b9a
5 changed files with 25 additions and 23 deletions

View File

@ -56,7 +56,7 @@ public final class ByteBufUtil {
private static final FastThreadLocal<byte[]> BYTE_ARRAYS = new FastThreadLocal<byte[]>() {
@Override
protected byte[] initialValue() throws Exception {
return PlatformDependent.allocateUninitializedArray(1024);
return PlatformDependent.allocateUninitializedArray(MAX_TL_ARRAY_LEN);
}
};
@ -95,6 +95,16 @@ public final class ByteBufUtil {
logger.debug("-Dio.netty.maxThreadLocalCharBufferSize: {}", MAX_CHAR_BUFFER_SIZE);
}
static final int MAX_TL_ARRAY_LEN = 1024;
/**
* Allocates a new array if minLength > {@link ByteBufUtil#MAX_TL_ARRAY_LEN}
*/
static byte[] threadLocalTempArray(int minLength) {
return minLength <= MAX_TL_ARRAY_LEN ? BYTE_ARRAYS.get()
: PlatformDependent.allocateUninitializedArray(minLength);
}
/**
* Returns a <a href="http://en.wikipedia.org/wiki/Hex_dump">hex dump</a>
* of the specified buffer's readable bytes.
@ -768,11 +778,7 @@ public final class ByteBufUtil {
array = src.array();
offset = src.arrayOffset() + readerIndex;
} else {
if (len <= 1024) {
array = BYTE_ARRAYS.get();
} else {
array = PlatformDependent.allocateUninitializedArray(len);
}
array = threadLocalTempArray(len);
offset = 0;
src.getBytes(readerIndex, array, 0, len);
}
@ -1392,7 +1398,9 @@ public final class ByteBufUtil {
int chunkLen = Math.min(length, WRITE_CHUNK_SIZE);
buffer.clear().position(position);
if (allocator.isDirectBufferPooled()) {
if (length <= MAX_TL_ARRAY_LEN || !allocator.isDirectBufferPooled()) {
getBytes(buffer, threadLocalTempArray(length), 0, chunkLen, out, length);
} else {
// if direct buffers are pooled chances are good that heap buffers are pooled as well.
ByteBuf tmpBuf = allocator.heapBuffer(chunkLen);
try {
@ -1402,9 +1410,6 @@ public final class ByteBufUtil {
} finally {
tmpBuf.release();
}
} else {
byte[] tmp = PlatformDependent.allocateUninitializedArray(length);
getBytes(buffer, tmp, 0, chunkLen, out, length);
}
}
}

View File

@ -17,7 +17,6 @@
package io.netty.buffer;
import io.netty.util.Recycler;
import io.netty.util.internal.PlatformDependent;
import java.io.IOException;
import java.io.InputStream;
@ -352,8 +351,8 @@ final class PooledDirectByteBuf extends PooledByteBuf<ByteBuffer> {
@Override
public int setBytes(int index, InputStream in, int length) throws IOException {
checkIndex(index, length);
byte[] tmp = PlatformDependent.allocateUninitializedArray(length);
int readBytes = in.read(tmp);
byte[] tmp = ByteBufUtil.threadLocalTempArray(length);
int readBytes = in.read(tmp, 0, length);
if (readBytes <= 0) {
return readBytes;
}

View File

@ -15,7 +15,6 @@
*/
package io.netty.buffer;
import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.StringUtil;
import java.io.IOException;
@ -356,11 +355,11 @@ class ReadOnlyByteBufferBuf extends AbstractReferenceCountedByteBuf {
if (buffer.hasArray()) {
out.write(buffer.array(), index + buffer.arrayOffset(), length);
} else {
byte[] tmp = PlatformDependent.allocateUninitializedArray(length);
byte[] tmp = ByteBufUtil.threadLocalTempArray(length);
ByteBuffer tmpBuf = internalNioBuffer();
tmpBuf.clear().position(index);
tmpBuf.get(tmp);
out.write(tmp);
tmpBuf.get(tmp, 0, length);
out.write(tmp, 0, length);
}
return this;
}

View File

@ -561,8 +561,8 @@ public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
if (buffer.hasArray()) {
return in.read(buffer.array(), buffer.arrayOffset() + index, length);
} else {
byte[] tmp = PlatformDependent.allocateUninitializedArray(length);
int readBytes = in.read(tmp);
byte[] tmp = ByteBufUtil.threadLocalTempArray(length);
int readBytes = in.read(tmp, 0, length);
if (readBytes <= 0) {
return readBytes;
}

View File

@ -584,7 +584,9 @@ final class UnsafeByteBufUtil {
buf.checkIndex(index, length);
if (length != 0) {
int len = Math.min(length, ByteBufUtil.WRITE_CHUNK_SIZE);
if (buf.alloc().isDirectBufferPooled()) {
if (len <= ByteBufUtil.MAX_TL_ARRAY_LEN || !buf.alloc().isDirectBufferPooled()) {
getBytes(addr, ByteBufUtil.threadLocalTempArray(length), 0, len, out, length);
} else {
// if direct buffers are pooled chances are good that heap buffers are pooled as well.
ByteBuf tmpBuf = buf.alloc().heapBuffer(len);
try {
@ -594,9 +596,6 @@ final class UnsafeByteBufUtil {
} finally {
tmpBuf.release();
}
} else {
byte[] tmp = PlatformDependent.allocateUninitializedArray(len);
getBytes(addr, tmp, 0, len, out, length);
}
}
}