Reputation: 83
So I have this MappedByteBuffer which has an int array stored in it (read from a file).
public static void read(String loc) {
try (FileChannel fileChannel = (FileChannel) Files.newByteChannel(
Paths.get(loc), EnumSet.of(StandardOpenOption.READ))) {
MappedByteBuffer mappedByteBuffer = fileChannel
.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
if (mappedByteBuffer != null) {
IntBuffer ib = mappedByteBuffer.asIntBuffer();
mappedByteBuffer.clear();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Now when I want to read the int array from the Buffer and use it in my code, I have to go with either the 2 ways below:
Way 1: (Copying the contents of the buffer (ints) into an int array)
int[] ar = new int[ib.capacity];
ib.get(ar);
int int_at_index_0 = ar[0];
Way 2: (Reading directly from the buffer)
ib.get(0); //reads int at index 0 directly
Now from what I understand, Way 1 copies the data stored on the direct buffer to heap memory which is something I do not want and defeats the purpose of using an Off-heap way of storage.
Way 2 get(index)
method just takes way too long as the data below shows:
Reading from an int[]
array: (copied from ByteBuffer)
ar[0]
takes 1928 nanoseconds.
Reading directly from ByteBuffer:
ib.get(0)
takes 18915 nanoseconds.
Big difference.
Does anyone know how I could read from the directbuffer/mappedbytebuffer FAST & without copying to heap memory (keeping it in Off-heap).
Upvotes: 1
Views: 262
Reputation: 2445
You can do it the way the Guava guys do store a small buffer (1024 bytes) in a ThreadLocal, use it if it suffices and never put a bigger buffer in the TL.
This'll work fine as long as most requests can be served by it. without some real testing it's hard to tell if it helps.
Google Guava ByteSource seems to be a good choice for buffering in memory. Unlike implementations like ByteArrayOutputStream or ByteArrayList(from Colt Library) it does not merge the data into a huge byte array but stores every chunk separately. An example:
List<ByteSource> result = new ArrayList<>();
try (InputStream source = httpRequest.getInputStream()) {
byte[] cbuf = new byte[CHUNK_SIZE];
while (true) {
int read = source.read(cbuf);
if (read == -1) {
break;
} else {
result.add(ByteSource.wrap(Arrays.copyOf(cbuf, read)));
}
}
}
ByteSource body = ByteSource.concat(result);
The ByteSource can be read as an InputStream anytime later:
InputStream data = body.openBufferedStream();
[Also you might check this out ][1]
Upvotes: 2