【发布时间】:2011-04-08 18:44:27
【问题描述】:
我正在编写一些SocketChannel-to-SocketChannel 代码,这些代码最适合使用直接字节缓冲区——寿命长且大(每个连接数十到数百兆字节)。同时散列出确切的循环FileChannels 的结构,我对 ByteBuffer.allocate() 与 ByteBuffer.allocateDirect() 的性能进行了一些微基准测试。
结果中有一个我无法解释的惊喜。在下图中,ByteBuffer.allocate() 传输实现在 256KB 和 512KB 处有一个非常明显的悬崖——性能下降了约 50%! ByteBuffer.allocateDirect() 似乎还有一个较小的性能悬崖。 (%-gain 系列有助于可视化这些变化。)
缓冲区大小(字节)与时间 (MS)
为什么ByteBuffer.allocate() 和ByteBuffer.allocateDirect() 之间出现奇怪的性能曲线差异?幕后究竟发生了什么?
这很可能取决于硬件和操作系统,所以这里有这些细节:
- 配备双核 Core 2 CPU 的 MacBook Pro
- 英特尔 X25M SSD 驱动器
- OSX 10.6.4
源代码,根据要求:
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);
}
}
【问题讨论】:
-
您是否将代码托管在某个地方?我很想看看我是否重新创建了你的结果。
-
@gid:已添加源代码。期待你的结果。
-
抱歉耽搁了,已经在 windows 7 x64 & java 1.6.20 上测试过,结果几乎一样。唯一的区别是下降发生在 256k 而不是 512k。
-
机器,Ubuntu 10.10 32 位,OpenJDK 1.6.0_20。我也测试过,在我的机器上,正常下降发生在 1024k,直接下降发生在 2048k。我想这种影响可能是由 OS/CPU 边界(CPU 缓存)上的某些东西引起的。
-
@bartosz.r:您的 CPU 的具体型号是什么?我也可以运行一些测试。
标签: java nio bytebuffer