zbb20180930 java,nio直接缓冲区与非直接缓冲区别

直接缓冲区与非直接缓冲区别

分散读取与聚集写入


非直接缓冲区

通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中!

案例展示

这里提供一个名为Python1,大小为397.1MB的zip文件;

现分别用直接缓冲区和非直接缓冲区对上面文件进行文件复制,看哪个缓冲区耗时最短,效率更高?

代码示例

public class NoStraightChannel {
    public static void main(String[] args) throws IOException {
        //利用通道完成文件的复制(非直接缓冲区)
        long start = System.currentTimeMillis();
        FileInputStream fis = new FileInputStream("/Users/yswKnight/Desktop/Python1.zip");
        FileOutputStream fos = new FileOutputStream("/Users/yswKnight/Desktop/Python2.zip");
        //1.获取通道
        FileChannel inChannel = fis.getChannel();
        FileChannel outChannel = fos.getChannel();
        //2.分配制定大小的缓冲区
        ByteBuffer allocate = ByteBuffer.allocate(1024);
        System.out.println(inChannel.read(allocate));
        while(inChannel.read(allocate)!=-1){
            //切换为读取数据
            allocate.flip();
            //3.将缓冲区中的数据写入通道中
            outChannel.write(allocate);
            allocate.clear();
        }
        inChannel.close();
        outChannel.close();

        fis.close();
        fos.close();

        long end=System.currentTimeMillis();
        System.out.println("非直接缓冲区完成文件复制所耗时:"+(end-start));
    }
}

运行结果

直接缓冲区

通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中。可以提高效率!

案例展示

代码示例

public class Channel {
    public static void main(String[] args) throws IOException {
        long start = System.currentTimeMillis();
        //使用直接缓冲区完成文件的复制(内存映射文件)
        FileChannel inChannel = FileChannel.open(Paths.get("/Users/yswKnight/Desktop/Python1.zip"), StandardOpenOption.READ);
        FileChannel outChannel = FileChannel.open(Paths.get("/Users/yswKnight/Desktop/Python2.zip"), StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE);
        //内存映射文件
        MappedByteBuffer inMap = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
        MappedByteBuffer outMap = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
        //直接对缓冲区进行数据的读写操作
        byte[] bytes = new byte[inMap.limit()];
        inMap.get(bytes);
        outMap.put(bytes);

        inChannel.close();
        outChannel.close();
        long end=System.currentTimeMillis();
        System.out.println("直接缓冲区完成文件复制所耗时:"+(end-start));

    }
}

运行结果

可以多运行几遍,看平均值!

总结:很明显,直接缓冲区比非直接缓冲区的效率要高出5倍之多!

字节缓冲区要么是直接的,要么是非直接的。

如果为直接字节缓冲区,则 Java 虚拟机会尽最大努力直接在此缓冲区上执行本机 I/O 操作。也就是说,

在每次调用基础操作系统的一个本机 I/O 操作之前(或之后),虚拟机都会尽量避免将缓冲区的内容复制到中间缓冲区中(或从中间缓冲区中复制内容)。

直接字节缓冲区可以通过调用此类的 allocateDirect() 工厂方法来创建。此方法返回的缓冲区进行分配和取消分配所需成本通常高于非直接缓冲区。

直接缓冲区的内容可以驻留在常规的垃圾回收堆之外,因此,它们对应用程序的内存需求量造成的影响可能并不明显。

所以,建议将直接缓冲区主要分配给那些易受基础系统的本机 I/O 操作影响的大型、持久的缓冲区。一般情况下,最好仅在直接缓冲区能在程序性能方面带来明显好处时分配它们。

直接字节缓冲区还可以通过 FileChannel 的 map() 方法 将文件区域直接映射到内存中来创建。该方法返回MappedByteBuffer 。 Java 平台的实现有助于通过 JNI 从本机代码创建直接字节缓冲区。

如果以上这些缓冲区中的某个缓冲区实例指的是不可访问的内存区域,则试图访问该区域不会更改该缓冲区的内容,并且将会在访问期间或稍后的某个时间导致抛出不确定的异常。

字节缓冲区是直接缓冲区还是非直接缓冲区可通过调用其 isDirect() 方法来确定。提供此方法是为了能够在性能关键型代码中执行显式缓冲区管理。


分散读取与聚集写入

分散读取(scattering Reads):

将通道中的数据分散到多个缓冲区中

聚集写入(gathering Writes):

将多个缓冲区的数据聚集到通道中

代码示例

public class GatheringChannel {
    public static void main(String[] args) throws IOException {
        RandomAccessFile rw = new RandomAccessFile("test.txt", "rw");
        //1.获取通道
        FileChannel channel = rw.getChannel();
        //2.分配指定大小的指定缓冲区
        ByteBuffer allocate1 = ByteBuffer.allocate(100);
        ByteBuffer allocate2 = ByteBuffer.allocate(1024);
        //3.分散读取
        ByteBuffer[] bufs={allocate1,allocate2};
        channel.read(bufs);

        for(ByteBuffer buffer:bufs){
            //切换为读取模式
            buffer.flip();
        }
        System.out.println("----------------分散读取allocate1缓冲区读100个字节-------------------");
        System.out.println(new String(bufs[0].array(),0,bufs[0].limit()));
        System.out.println("----------------分散读取allocate2缓冲区读1024个字节-------------------");
        System.out.println(new String(bufs[1].array(),0,bufs[1].limit()));

        //聚集写入
        RandomAccessFile rw2 = new RandomAccessFile("test2.txt", "rw");
        FileChannel Channel2 = rw2.getChannel();
        Channel2.write(bufs);
        //执行成功后会新生成一个test2.txt文件,里面的内容跟test.txt相似!

    }
}

运行结果

--------------------- 本文来自 詠聖wK 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/yswKnight/article/details/79339848?utm_source=copy

原文地址:https://www.cnblogs.com/super-admin/p/9729082.html

时间: 2024-10-11 00:44:58

zbb20180930 java,nio直接缓冲区与非直接缓冲区别的相关文章

Java NIO -- 直接缓冲区与非直接缓冲区

直接缓冲区与非直接缓冲区: 非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中直接缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建立在物理内存中.可以提高效率 字节缓冲区要么是直接的,要么是非直接的.如果为直接字节缓冲区,则 Java 虚拟机会尽最大努力直接在机 此缓冲区上执行本机 I/O 操作.也就是说,在每次调用基础操作系统的一个本机 I/O 操作之前(或之后), 虚拟机都会尽量避免将缓冲区的内容复制到中间缓冲区中(或从中

NIO直接缓冲区和非直接缓冲区

非直接缓冲区:通过allocate()方法分配缓冲区,将缓冲区建立在JVM的内存中. 直接缓冲区:通过allocateDirect()方法分配直接缓冲区,将缓冲区建立在物理内存中.可以提高效率. 字节缓冲区要么是直接的,要么是非直接的.如果为直接字节缓冲区,则 Java 虚拟机会尽最大努力直接在此缓冲区上执行本机 I/O 操作.也就是说,在每次调用基础操作系统的一个本机 I/O 操作之前(或之后),虚拟机都会尽量避免将缓冲区的内容复制到中间缓冲区中(或从中间缓冲区中复制内容). 直接字节缓冲区可

Java NIO 之缓冲区

一个 Buffer 对象是固定数量的数据的容器.通道是 I/O 传输发生时通过的入口,而缓冲区是这些数据传输的来源或目标. 缓冲区基础 所有的缓冲区都具有四个属性来 供关于其所包含的数据元素的信息. capacity(容量):缓冲区能够容纳数据的最大值,创建缓冲区后不能改变. limit(上界):缓冲区的第一个不能被读或写的元素.或者,缓冲区现存元素的计数. position(位置):下一个要被读或写的元素的索引.调用 get 或 put 函数会更新. mark(标记):一个备忘位置.调用 ma

Java NIO之缓冲区

简介 IO概念 缓冲区操作 虚拟内存 文件IO 流IO 缓冲区 Buffer属性 Buffer数据填充.翻转.释放.压缩.标记 Buffer比较 Buffer批量移动 复制缓冲区 字节缓冲区 直接缓冲区 其他缓冲区 简介 几个IO事实: 影响应用程序执行效率的限定因素,往往非处理速率,而是IO OS要移动大块数据,往往是在DMA协助下完成,而JVM的IO操作往往是小块数据,有了NIO,可改变这种情况 JDK1.4,java.nio提供了一套新的抽象用于IO处理 IO概念 缓冲区操作 进程执行IO

Java中static静态与非静态的区别

先前看到一个技术大牛写了一个关于静态成员与非静态成员,静态方法和非静态方法的各自区别,觉得挺好的,在这里写一个小程序来说明这些区别. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package com.liaojianya.chapter5; /**  * This program will de

java.nio.ByteBuffer 以及flip,clear及rewind区别

Buffer 类 定义了一个可以线性存放primitive type数据的容器接口.Buffer主要包含了与类型(byte, char…)无关的功能. 值得注意的是Buffer及其子类都不是线程安全的. 每个Buffer都有以下的属性: capacity这个Buffer最多能放多少数据.capacity一般在buffer被创建的时候指定. limit在Buffer上进行的读写操作都不能越过这个下标.当写数据到buffer中时,limit一般和capacity相等,当读数据时,limit代表buf

java NIO-Channel

基本简介 Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式. Java NIO: Channels and Buffers(通道和缓冲区) 标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中. Java NIO: Non-blocking IO(非阻塞IO) Java

Java Nio 十四、Java NIO vs. IO

最后更新时间:2014-06-23 当学习Java NIO和IO的API的时候,一个问题很快的就会出现中我们的脑中: 我什么时候应该使用IO,什么时候应该使用NIO? 在这篇文章中我将会尝试着写出中NIO和IO之间不同的地方,他们的使用场景,以及他们怎么影响你的代码设计. Java NIO和IO的主要不同 下面的表格总结了Java NIO和IO的主要不同.针对这个表格中的不同点我将会给予更加详细的说明. IO NIO 基于流的 基于缓冲区的 堵塞IO 非堵塞IO   Selectors(选择器)

Java NIO 学习总结 学习手册

原文 并发编程网(翻译):http://ifeve.com/java-nio-all/  源自 http://tutorials.jenkov.com/java-nio/index.html Java NIO: Channels and Buffers(通道和缓冲区) 标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中. Java NIO: Non-blocking IO(非阻塞IO