直接内存由操作系统来管理。常见于NIO,用于数据缓冲,读写性能很高,分配回收花销较高。

使用以下代码来比较使用传统方式读写与NIO读写的区别,注意第一次启动读写性能会较差,需多运行几次,计算平均值。

/**
 * 演示 ByteBuffer 作用
 */
public class Demo1_9 {
    static final String FROM = "F:\\博客\\谷粒学院实践项目.md";
    static final String TO = "F:\\谷粒学院实践项目.md";
    static final int _1Mb = 1024 * 1024;

    public static void main(String[] args) {
        io(); // io 用时:1535.586957 1766.963399 1359.240226
        directBuffer(); // directBuffer 用时:479.295165 702.291454 562.56592
    }

    private static void directBuffer() {
        long start = System.nanoTime();
        try (FileChannel from = new FileInputStream(FROM).getChannel();
             FileChannel to = new FileOutputStream(TO).getChannel();
        ) {
            ByteBuffer bb = ByteBuffer.allocateDirect(_1Mb);
            while (true) {
                int len = from.read(bb);
                if (len == -1) {
                    break;
                }
                bb.flip();
                to.write(bb);
                bb.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        long end = System.nanoTime();
        System.out.println("directBuffer 用时:" + (end - start) / 1000_000.0);
    }

    private static void io() {
        long start = System.nanoTime();
        try (FileInputStream from = new FileInputStream(FROM);
             FileOutputStream to = new FileOutputStream(TO);
        ) {
            byte[] buf = new byte[_1Mb];
            while (true) {
                int len = from.read(buf);
                if (len == -1) {
                    break;
                }
                to.write(buf, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        long end = System.nanoTime();
        System.out.println("io 用时:" + (end - start) / 1000_000.0);
    }
}

为什么直接内存读写效率高?使用阻塞式io进行读写cpu和内存的变化如下图。很显然,从系统缓存区将文件复制到java缓存区是一个耗时且不必要的复制。
图片说明

使用Nio进行读写cpu和内存的变化如下图。操作系统在allocateDirect()方法执行时会分配一块直接内存,这部分内存java代码和系统都可以进行访问。

图片说明