java.io的FileInputStream/FileOutputStream或者java.nio的transferTo/transferFrom。
nio方式可能更快,因为使用了零拷贝技术,数据传输不需要切换到用户态参与,减少了上下文切换和不必要的内存拷贝。
比如应用读取数据时,先在内核态将数据从磁盘读取到内核缓存,再切换到用户态将数据从内核缓存读取到用户缓存。
而NIO transferTo则直接在内核中进行数据拷贝。
-XX:MaxDirectMemorySize=512M
BytBuffer分配在堆内: ByteBuffer buf = ByteBuffer.allocate(1024);
ByteBuffer分配在堆外 ByteBuffer buf = ByteBuffer.allocateDirect(1024);
对比一下allocate方法和allocateDirect方法:
public static ByteBuffer allocateDirect(int capacity) {
return new DirectByteBuffer(capacity);
}
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}
DirectBuffer.allocateDirect(int capacity)是调用了本地方法malloc去申请一块内存。
DirectBuffer创建效率其实比Heap Buffer低,因为java对象在java堆内申请内存只需要不足10条机器指令,而Direct Buffer调用malloc需要60~100条CPU指令。
DirectBuffer比较快:
static int write(FileDescriptor fd, ByteBuffer src, long position,
NativeDispatcher nd)
throws IOException
{
if (src instanceof DirectBuffer)
return writeFromNativeBuffer(fd, src, position, nd);
// Substitute a native buffer
int pos = src.position();
int lim = src.limit();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
try {
bb.put(src);
bb.flip();
// ................略
可以看到,如果是direct,则调用writeFromNativeBuffer,如果不是,则需要创建一个临时的Buffer,把src拷贝进去。之所以这样做,是因为writeFromNativeBuffer的实现,会把buffer的地址传给OS,这块内存不能动,但是GC可能会搬动java推的东西,所以只能弄一块地址不会变的内存。
问题: