8193832: Performance of InputStream.readAllBytes() could be improved

Read into a list of fixed-size buffers which are gathered at the end

Reviewed-by: alanb, chegar, plevart, jrose, psandoz
This commit is contained in:
Brian Burkhalter 2017-12-22 14:00:03 -08:00
parent d32979d771
commit 1209c4bcb3
2 changed files with 53 additions and 30 deletions
src/java.base/share/classes/java/io
test/jdk/java/io/InputStream

@ -25,7 +25,9 @@
package java.io;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
@ -229,30 +231,55 @@ public abstract class InputStream implements Closeable {
* @since 9
*/
public byte[] readAllBytes() throws IOException {
byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
int capacity = buf.length;
int nread = 0;
List<byte[]> bufs = null;
byte[] result = null;
int total = 0;
int n;
for (;;) {
// read to EOF which may read more or less than initial buffer size
while ((n = read(buf, nread, capacity - nread)) > 0)
do {
byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
int nread = 0;
// read to EOF which may read more or less than buffer size
while ((n = read(buf, nread, buf.length - nread)) > 0) {
nread += n;
// if the last call to read returned -1, then we're done
if (n < 0)
break;
// need to allocate a larger buffer
if (capacity <= MAX_BUFFER_SIZE - capacity) {
capacity = capacity << 1;
} else {
if (capacity == MAX_BUFFER_SIZE)
throw new OutOfMemoryError("Required array size too large");
capacity = MAX_BUFFER_SIZE;
}
buf = Arrays.copyOf(buf, capacity);
if (nread > 0) {
if (MAX_BUFFER_SIZE - total < nread) {
throw new OutOfMemoryError("Required array size too large");
}
total += nread;
if (result == null) {
result = buf;
} else {
if (bufs == null) {
bufs = new ArrayList<>();
bufs.add(result);
}
bufs.add(buf);
}
}
} while (n >= 0); // if the last call to read returned -1, then break
if (bufs == null) {
if (result == null) {
return new byte[0];
}
return result.length == total ?
result : Arrays.copyOf(result, total);
}
return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
result = new byte[total];
int offset = 0;
int remaining = total;
for (byte[] b : bufs) {
int len = Math.min(b.length, remaining);
System.arraycopy(b, 0, result, offset, len);
offset += len;
remaining -= len;
}
return result;
}
/**

@ -31,7 +31,7 @@ import jdk.test.lib.RandomFactory;
/*
* @test
* @bug 8080835
* @bug 8080835 8193832
* @library /test/lib
* @build jdk.test.lib.RandomFactory
* @run main ReadAllBytes
@ -47,15 +47,11 @@ public class ReadAllBytes {
test(new byte[]{});
test(new byte[]{1, 2, 3});
test(createRandomBytes(1024));
test(createRandomBytes((1 << 13) - 1));
test(createRandomBytes((1 << 13)));
test(createRandomBytes((1 << 13) + 1));
test(createRandomBytes((1 << 15) - 1));
test(createRandomBytes((1 << 15)));
test(createRandomBytes((1 << 15) + 1));
test(createRandomBytes((1 << 17) - 1));
test(createRandomBytes((1 << 17)));
test(createRandomBytes((1 << 17) + 1));
for (int shift : new int[] {13, 14, 15, 17}) {
for (int offset : new int[] {-1, 0, 1}) {
test(createRandomBytes((1 << shift) + offset));
}
}
}
static void test(byte[] expectedBytes) throws IOException {