Warum die ungeraden Leistungskurvenunterschiede zwischen ByteBuffer.allocate () und ByteBuffer.allocateDirect ()
Ich arbeite an einigenSocketChannel
-zuSocketChannel
Code, der am besten mit einem direkten Byte-Puffer funktioniert - langlebig und groß (Zehn bis Hunderte von Megabyte pro VerbindungFileChannel
s, ich habe einige Micro-Benchmarks auf @ ausgefühByteBuffer.allocate()
vs.ByteBuffer.allocateDirect()
performance.
Es gab eine Überraschung in den Ergebnissen, die ich nicht wirklich erklären kann. In der folgenden Grafik gibt es eine sehr ausgeprägte Klippe bei den 256 KB und 512 KB für dieByteBuffer.allocate()
transfer-Implementierung - die Leistung sinkt um ~ 50%! Es scheint auch eine kleinere Performance-Klippe für das @ zu gebeByteBuffer.allocateDirect()
. (Die% -gain-Reihe hilft, diese Änderungen zu visualisieren.)
Buffer Size (Bytes) gegen Time (MS)
Warum die ungerade Leistungskurvendifferenz zwischenByteBuffer.allocate()
undByteBuffer.allocateDirect()
? Was genau ist hinter dem Vorhang los?
Es hängt sehr gut von der Hardware und dem Betriebssystem ab, also hier die Details:
MacBook Pro mit Dual-Core Core 2-CPUIntel X25M SSD-LaufwerkOSX 10.6.4Quellcode, auf Anfrage:
package ch.dietpizza.bench;
import static java.lang.String.format;
import static java.lang.System.out;
import static java.nio.ByteBuffer.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
public class SocketChannelByteBufferExample {
private static WritableByteChannel target;
private static ReadableByteChannel source;
private static ByteBuffer buffer;
public static void main(String[] args) throws IOException, InterruptedException {
long timeDirect;
long normal;
out.println("start");
for (int i = 512; i <= 1024 * 1024 * 64; i *= 2) {
buffer = allocateDirect(i);
timeDirect = copyShortest();
buffer = allocate(i);
normal = copyShortest();
out.println(format("%d, %d, %d", i, normal, timeDirect));
}
out.println("stop");
}
private static long copyShortest() throws IOException, InterruptedException {
int result = 0;
for (int i = 0; i < 100; i++) {
int single = copyOnce();
result = (i == 0) ? single : Math.min(result, single);
}
return result;
}
private static int copyOnce() throws IOException, InterruptedException {
initialize();
long start = System.currentTimeMillis();
while (source.read(buffer)!= -1) {
buffer.flip();
target.write(buffer);
buffer.clear(); //pos = 0, limit = capacity
}
long time = System.currentTimeMillis() - start;
rest();
return (int)time;
}
private static void initialize() throws UnknownHostException, IOException {
InputStream is = new FileInputStream(new File("/Users/stu/temp/robyn.in"));//315 MB file
OutputStream os = new FileOutputStream(new File("/dev/null"));
target = Channels.newChannel(os);
source = Channels.newChannel(is);
}
private static void rest() throws InterruptedException {
System.gc();
Thread.sleep(200);
}
}