I've faced an interesting thing today regarding RandomAccessFile
.
I've noticed that using RandomAccessFile
's writeInt(int i)
method is much more slower than using RandomAccessFile
's write(byte[] b)
where I first convert int value to byte[4] array.
I'm doing the conversion with this code
private static byte[] intToByte(int i)
{
byte[] result = new byte[4];
result[0] = (byte) (i >> 24);
result[1] = (byte) (i >> 16);
result[2] = (byte) (i >> 8);
result[3] = (byte) (i);
return result;
}
The difference is very significant, favoring write(byte[] b)
.
Writing 1 million int
s on my laptop with JDK 8:
writeInt(int i)
method took ~9 seconds write(byte[] b)
took ~2,3 seconds I have similar results in another environment, where I'm using JDK 7 and a totally different machine.
The writeInt(int i) method delegate to native write0(int b)
method and write(byte[] b)
delegates to native writeBytes
.
When I did profiling I've noticed that the majority of the execution time was spent in writeInt
method when it was used.
Does anyone know why I see such a big difference? Seems like writeInt
is way less efficient.
RandomAccessFile has actually two native methods to write bytes:
//writes an array
private native void writeBytes(byte b[], int off, int len) throws IOException;
and
//writes one byte
public native void write(int b) throws IOException;
the method writeInt(int) writes each byte separately with the native write(int) method, while write(byte[]) uses the native writeBytes(byte[],int,int) method.
the writeInt method does 4 method invocations to write each byte of the passed integer value, the other method uses only one invocation to write the array. Method invocations are actually expensive operations in java: for each invocation the JVM allocates additional memory for the operand stack and the local variables array.
Not going to go into details of the changes that I made, but your tests are a little bit flawed. I took the liberty of updating them a little and ran a few tests too:
@BenchmarkMode(value = { Mode.AverageTime })
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Warmup(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS)
public class RandomAccessWriteFileTest {
public static void main(String[] args) throws Exception {
Options opt = new OptionsBuilder().include(RandomAccessWriteFileTest.class.getSimpleName())
.jvmArgs("-ea")
.shouldFailOnError(true)
.build();
new Runner(opt).run();
}
@Benchmark()
@Fork(1)
public long benchamrkWriteDirectInt(BenchmarkPlainIntSetup setupTest) {
try {
setupTest.raf.writeInt(6969);
return setupTest.raf.length();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Benchmark()
@Fork(1)
public long benchamrkWriteConvertedInt(BenchmarkConvertedIntSetup setupTest) {
try {
setupTest.raf.write(intToBytes(6969));
return setupTest.raf.length();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static byte[] intToBytes(int i) {
byte[] result = new byte[4];
result[0] = (byte) (i >> 24);
result[1] = (byte) (i >> 16);
result[2] = (byte) (i >> 8);
result[3] = (byte) i;
return result;
}
@State(Scope.Thread)
static public class BenchmarkConvertedIntSetup {
public RandomAccessFile raf;
public File f;
@Setup(Level.Iteration)
public void setUp() {
try {
f = new File("jmhDirectIntBenchamrk.ser" + ThreadLocalRandom.current().nextInt());
raf = new RandomAccessFile(f, "rw");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
@TearDown(Level.Iteration)
public void tearDown() {
f.delete();
}
}
@State(Scope.Thread)
static public class BenchmarkPlainIntSetup {
public RandomAccessFile raf;
public File f;
@Setup(Level.Iteration)
public void setUp() {
try {
f = new File("jmhDirectIntBenchamrk.ser" + ThreadLocalRandom.current().nextInt());
raf = new RandomAccessFile(f, "rw");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
@TearDown(Level.Iteration)
public void tearDown() {
f.delete();
}
}
}
Absolutely there is a difference in results (these are ms per operation)
benchamrkWriteConvertedInt 0.008
benchamrkWriteDirectInt 0.026
No idea why (may be will dig the assembly to understand some time later, but I can confirm your findings. good question!)
This was run with latest java-8 and java-9 btw
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.