非直接缓冲区:经过 allocate() 方法分配缓冲区,将缓冲区创建在 JVM 的内存中安全
上图读的过程: 读物理磁盘文件时候,先到物理内存读到,而后拷贝到jvm内存中。 程序去jvm读取。 从物理空间拷贝到jvm内存空间,效率慢。app
写的过程: 先写到jvm内存,jvm拷贝到物理内存,而后再到物理磁盘。jvm
非直接缓冲区 直接存放在 jvm缓冲区 须要来回copy性能
非直接缓冲区 存放在物理内存 不须要copyspa
存放在物理内存比jvm缓冲区效率高 操作系统
直接缓冲区:经过 allocateDirect() 方法分配直接缓冲区,将缓冲区创建在物理内存中。能够提升效率code
非直接缓冲区:blog
应用程序 不走jvm内存和物理内存。 走的是物理内存映射文件。内存条ip
写: 直接写到物理内存映射文件,到物理磁盘内存
读: 物理磁盘文件读到物理内存映射文件,而后读取之
直接缓冲区 占内存 不安全 可是效率高
字节缓冲区要么是直接的,要么是非直接的。若是为直接字节缓冲区,则 Java 虚拟机会尽最大努力直接在此缓冲区上执行本机 I/O 操做。也就是说,在每次调用基础操做系统的一个本机 I/O 操做以前(或以后),虚拟机都会尽可能避免将缓冲区的内容复制到中间缓冲区中(或从中间缓冲区中复制内容)。
直接字节缓冲区能够经过调用此类的 allocateDirect() 工厂方法来建立。此方法返回的缓冲区进行分配和取消分配所需成本一般高于非直接缓冲区。直接缓冲区的内容能够驻留在常规的垃圾回收堆以外,所以,它们对应用程序的内存需求量形成的影响可能并不明显。因此,建议将直接缓冲区主要分配给那些易受基础系统的本机 I/O 操做影响的大型、持久的缓冲区。通常状况下,最好仅在直接缓冲区能在程序性能方面带来明显好处时分配它们。
直接字节缓冲区还能够经过 FileChannel 的 map() 方法 将文件区域直接映射到内存中来建立。该方法返回MappedByteBuffer 。 Java 平台的实现有助于经过 JNI 从本机代码建立直接字节缓冲区。若是以上这些缓冲区中的某个缓冲区实例指的是不可访问的内存区域,则试图访问该区域不会更改该缓冲区的内容,而且将会在访问期间或稍后的某个时间致使抛出不肯定的异常。
字节缓冲区是直接缓冲区仍是非直接缓冲区可经过调用其 isDirect() 方法来肯定。提供此方法是为了可以在性能关键型代码中执行显式缓冲区管理。
IO缓冲区 非直接缓冲区
// 使用直接缓冲区完成文件的复制(内存映射文件) static public void test2() throws IOException { long start = System.currentTimeMillis(); FileChannel inChannel = FileChannel.open(Paths.get("f://1.mp4"), StandardOpenOption.READ); FileChannel outChannel = FileChannel.open(Paths.get("f://2.mp4"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE); // 内存映射文件 MappedByteBuffer inMappedByteBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size()); MappedByteBuffer outMappedByteBuffer = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size()); // 直接对缓冲区进行数据的读写操做 byte[] dsf = new byte[inMappedByteBuf.limit()]; inMappedByteBuf.get(dsf); outMappedByteBuffer.put(dsf); inChannel.close(); outChannel.close(); long end = System.currentTimeMillis(); System.out.println(end - start); } // 1.利用通道完成文件的复制(非直接缓冲区) static public void test1() throws IOException { // 4400 long start = System.currentTimeMillis(); FileInputStream fis = new FileInputStream("f://1.mp4"); FileOutputStream fos = new FileOutputStream("f://2.mp4"); // ①获取通道 FileChannel inChannel = fis.getChannel(); FileChannel outChannel = fos.getChannel(); // ②分配指定大小的缓冲区 ByteBuffer buf = ByteBuffer.allocate(1024); while (inChannel.read(buf) != -1) { buf.flip();// 切换为读取数据 // ③将缓冲区中的数据写入通道中 outChannel.write(buf); buf.clear(); } outChannel.close(); inChannel.close(); fos.close(); fis.close(); long end = System.currentTimeMillis(); System.out.println(end - start); }