Fix for #3853
Removes the following allocations: - ``CharsetDecoder`` is reused between calls - ``CharBuffer#wrap`` removed in favor of heap based char buffer that is reused - Temporary ``char[]``, an intermediate copy inside ``StringCoding`` - Another ``char[]``, this is needed because ``StringCoding`` uses a ``CharBuffer`` internally but returns a ``char[]``. Extra characters need to be trimmed so this means yet another allocation - Yet another ``char[]`` directly from ``__string`` for non-heap based buffers Removes the following copies - No copy is performed to trim the allocation since a ``CharBuffer`` is used directly - For non-heap based byte buffers, removes the copy that was previously done in the __string function This does need to get the TLS entry which implies at least some contention on the thread object table and a fence.
This commit is contained in:
parent
6f751d5d26
commit
286587d151
|
@ -19,6 +19,11 @@ package com.google.flatbuffers;
|
||||||
import static com.google.flatbuffers.Constants.*;
|
import static com.google.flatbuffers.Constants.*;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.CharBuffer;
|
||||||
|
import java.nio.charset.CharacterCodingException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.CharsetDecoder;
|
||||||
|
import java.nio.charset.CoderResult;
|
||||||
|
|
||||||
/// @cond FLATBUFFERS_INTERNAL
|
/// @cond FLATBUFFERS_INTERNAL
|
||||||
|
|
||||||
|
@ -26,6 +31,13 @@ import java.nio.ByteOrder;
|
||||||
* All tables in the generated code derive from this class, and add their own accessors.
|
* All tables in the generated code derive from this class, and add their own accessors.
|
||||||
*/
|
*/
|
||||||
public class Table {
|
public class Table {
|
||||||
|
private final static ThreadLocal<CharsetDecoder> UTF8_DECODER = new ThreadLocal<CharsetDecoder>() {
|
||||||
|
@Override
|
||||||
|
protected CharsetDecoder initialValue() {
|
||||||
|
return Charset.forName("UTF-8").newDecoder();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private final static ThreadLocal<CharBuffer> CHAR_BUFFER = new ThreadLocal<CharBuffer>();
|
||||||
/** Used to hold the position of the `bb` buffer. */
|
/** Used to hold the position of the `bb` buffer. */
|
||||||
protected int bb_pos;
|
protected int bb_pos;
|
||||||
/** The underlying ByteBuffer to hold the data of the Table. */
|
/** The underlying ByteBuffer to hold the data of the Table. */
|
||||||
|
@ -71,20 +83,34 @@ public class Table {
|
||||||
* @return Returns a `String` from the data stored inside the FlatBuffer at `offset`.
|
* @return Returns a `String` from the data stored inside the FlatBuffer at `offset`.
|
||||||
*/
|
*/
|
||||||
protected String __string(int offset) {
|
protected String __string(int offset) {
|
||||||
|
CharsetDecoder decoder = UTF8_DECODER.get();
|
||||||
|
decoder.reset();
|
||||||
|
|
||||||
offset += bb.getInt(offset);
|
offset += bb.getInt(offset);
|
||||||
if (bb.hasArray()) {
|
ByteBuffer src = bb.duplicate().order(ByteOrder.LITTLE_ENDIAN);
|
||||||
return new String(bb.array(), bb.arrayOffset() + offset + SIZEOF_INT, bb.getInt(offset),
|
int length = src.getInt(offset);
|
||||||
FlatBufferBuilder.utf8charset);
|
src.position(offset + SIZEOF_INT);
|
||||||
} else {
|
src.limit(offset + SIZEOF_INT + length);
|
||||||
// We can't access .array(), since the ByteBuffer is read-only,
|
|
||||||
// off-heap or a memory map
|
int required = (int)((float)length * decoder.maxCharsPerByte());
|
||||||
ByteBuffer bb = this.bb.duplicate().order(ByteOrder.LITTLE_ENDIAN);
|
CharBuffer dst = CHAR_BUFFER.get();
|
||||||
// We're forced to make an extra copy:
|
if (dst == null || dst.capacity() < required) {
|
||||||
byte[] copy = new byte[bb.getInt(offset)];
|
dst = CharBuffer.allocate(Math.max(required, 128));
|
||||||
bb.position(offset + SIZEOF_INT);
|
CHAR_BUFFER.set(dst);
|
||||||
bb.get(copy);
|
|
||||||
return new String(copy, 0, copy.length, FlatBufferBuilder.utf8charset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dst.clear();
|
||||||
|
|
||||||
|
try {
|
||||||
|
CoderResult cr = decoder.decode(src, dst, true);
|
||||||
|
if (!cr.isUnderflow()) {
|
||||||
|
cr.throwException();
|
||||||
|
}
|
||||||
|
} catch (CharacterCodingException x) {
|
||||||
|
throw new Error(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dst.flip().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue