直接内存由操作系统来管理。常见于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代码和系统都可以进行访问。