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推的东西,所以只能弄一块地址不会变的内存。
问题: