直接缓冲区与非直接缓冲区的概念

一、非直接缓冲区

1)创建方式

通过

static ByteBuffer allocate(int capacity)

创建的缓冲区,在JVM中内存中创建,在每次调用基础操作系统的一个本机IO之前或者之后,虚拟机都会将缓冲区的内容复制到中间缓冲区(或者从中间缓冲区复制内容),缓冲区的内容驻留在JVM内,因此销毁容易,但是占用JVM内存开销,处理过程中有复制操作。

2)写入步骤

1.创建一个临时的直接ByteBuffer对象。
2.将非直接缓冲区的内容复制到临时缓冲中。
3.使用临时缓冲区执行低层次I/O操作。
4.临时缓冲区对象离开作用域,并最终成为被回收的无用数据。

二、直接缓冲区

1)创建方式

通过

static ByteBuffer allocateDirect(int capacity)

创建的缓冲区,在JVM内存外开辟内存,在每次调用基础操作系统的一个本机IO之前或者之后,虚拟机都会避免将缓冲区的内容复制到中间缓冲区(或者从中间缓冲区复制内容),缓冲区的内容驻留在物理内存内,会少一次复制过程,如果需要循环使用缓冲区,用直接缓冲区可以很大地提高性能。虽然直接缓冲区使JVM可以进行高效的I/O操作,但它使用的内存是操作系统分配的,绕过了JVM堆栈,建立和销毁比堆栈上的缓冲区要更大的开销。

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

  1. 字节缓冲区要么是直接的,要么是非直接的。如果为直接字节缓冲区,则 Java 虚拟机会尽最大努力直接在此缓冲区上执行本机 I/O 操作。也就是说,在每次调用基础操作系统的一个本机 I/O 操作之前(或之后),虚拟机都会尽量避免将缓冲区的内容复制到中间缓冲区中(或从中间缓冲区中复制内容)。
  2. 直接字节缓冲区可以通过调用此类的 allocateDirect() 工厂方法来创建。此方法返回的缓冲区进行分配和取消分配所需成本通常高于非直接缓冲区。直接缓冲区的内容可以驻留在常规的垃圾回收堆之外,因此,它们对应用程序的内存需求量造成的影响可能并不明显。所以,建议将直接缓冲区主要分配给那些易受基础系统的本机 I/O 操作影响的大型、持久的缓冲区。一般情况下,最好仅在直接缓冲区能在程序性能方面带来明显好处时分配它们。
  3. 直接字节缓冲区还可以通过 FileChannel 的 map() 方法 将文件区域直接映射到内存中来创建。该方法返回MappedByteBuffer 。 Java 平台的实现有助于通过 JNI 从本机代码创建直接字节缓冲区。如果以上这些缓冲区中的某个缓冲区实例指的是不可访问的内存区域,则试图访问该区域不会更改该缓冲区的内容,并且将会在访问期间或稍后的某个时间导致抛出不确定的异常。
  4. 字节缓冲区是直接缓冲区还是非直接缓冲区可通过调用其 isDirect() 方法来确定。提供此方法是为了能够在性能关键型代码中执行显式缓冲区管理。

直接缓冲区与非直接缓冲区区别图形示意

物理磁盘->内核地址空间->用户地址空间->应用程序
OS                              ->                           JVM

直接缓冲区:内核地址空间和用户地址空间之间形成了一个物理内存映射文件,减少了之间的copy过程。

这边可以看下jvm结构里的直接内存:JVM虚拟机(一):java虚拟机的基本结构

代码示例

 package com.expgiga.NIO;

 import java.nio.ByteBuffer;

 /**
* 一、缓冲区(Buffer):在Java NIO中负责数据的存取,缓冲区就是数组,用于存储不同数据类型的数据。
* 根据数据类型不同(boolean除外),提供了相应类型的缓冲区
*
* ByteBuffer
* CharBuffer
* ShortBuffer
* IntBuffer
* LongBuffer
* FloatBuffer
* DoubleBuffer
*
* 这些缓冲区的管理方式几乎一致,通过allocate()获取缓冲区。
*
* 二、缓冲区存取数据的两个核心的方法:
* put() 存入数据到缓冲区
* get() 获取缓冲区的数据
*
* 三、缓冲区中的四个核心属性:
* capacity:容量,表示缓冲区中最大的存储数据的容量,一旦声明不能改变
* limit:界限,表示缓冲区中可以操作数据的大小。(limit后数据不能进行读写)
* position:位置,表示缓冲区中正在操作数据的位置。
* 0 <= mark <= position <= limit <= capacity
* mark:标记,表示记录当前position的位置,通过reset()恢复到mark的位置
*
* 四、直接缓冲区和非直接缓冲区
* 非直接缓冲区:通过allocate()分配缓冲区,将缓冲区建立在JVM的内存中
* 直接缓冲区:通过allocateDirect()分配直接缓冲区,将缓冲区建立在物理内存中,可以提高效率。
*/
public class TestBuffer { public static void main(String[] args) { String str = "abcde"; //1.分配一个指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024); System.out.println("-----------allocate()----------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity());//0 1024 1024 //2.利用put()存入数据到缓冲区
buf.put(str.getBytes());
System.out.println("-----------put()----------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity()); //5 1024 1024 //3.利用flip()切换成读数据模式
buf.flip();
System.out.println("-----------flip()----------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity()); //0 5 1024 //4.利用get()读取缓冲区中的数据
byte[] dst = new byte[buf.limit()];
buf.get(dst);
System.out.println(new String(dst, 0, dst.length));
System.out.println("-----------get()----------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity()); //5 5 1024 //5.rewind()可重复读数据
buf.rewind();
System.out.println("-----------rewind()----------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity()); //0 5 1024 //6.清空缓冲区,但是缓冲区里面的数据依然存在,数据存在被遗忘状态
buf.clear();
System.out.println("-----------clear()----------");
System.out.println(buf.position());
System.out.println(buf.limit());
System.out.println(buf.capacity()); //0 1024 1024 System.out.println((char)buf.get());//a //--------------------------------------------------------------
String str2 = "abcde";
ByteBuffer buf2 = ByteBuffer.allocate(1024);
buf2.put(str2.getBytes()); buf2.flip(); byte[] dst2 = new byte[buf.limit()];
buf2.get(dst2, 0, 2); System.out.println(new String(dst2, 0, 2));
System.out.println(buf2.position());//2 //mark() 标记
buf2.mark(); buf2.get(dst2, 2, 2);
System.out.println(new String(dst2, 2, 2));
System.out.println(buf2.position());//4 //reset()恢复到mark的位置
buf2.reset();
System.out.println(buf2.position());//2 //--------------------------------------------------------------
//分配直接缓冲区
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
System.out.println(buffer.isDirect()); //判断是否是直接缓冲区
}
}

NIO之直接缓冲区与非直接缓冲区的更多相关文章

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

    直接缓冲区与非直接缓冲区: 非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中直接缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建 ...

  2. Java-NIO(三):直接缓冲区与非直接缓冲区

    直接缓冲区与非直接缓冲区的概念: 1)非直接缓冲区:通过 static ByteBuffer allocate(int capacity) 创建的缓冲区,在JVM中内存中创建,在每次调用基础操作系统的 ...

  3. 基于直接缓冲区和非直接缓冲区的javaIO文件操作

    基本概念: 1. 非直接缓冲区:  指的是通过jvm来缓存数据的,应用程序要读取本地数据要经历从本地磁盘到物理内存,然后copy到jvm中,然后再通过流的方式读取到应用程序中,写的操作正好与之相反. ...

  4. java NIO 直接与非直接缓冲区

    ByteBuffer有两个创建缓冲区的方法:static ByteBuffer allocate(int capacity)static ByteBuffer allocateDirect(int c ...

  5. 使用非直接缓冲区与直接缓冲区进行文件的复制(基于Channel)

    一.利用通道完成文件的复制(非直接缓冲区)     long start = System.currentTimeMillis(); FileInputStream fis = new FileInp ...

  6. MPI - 缓冲区和非阻塞通信

    转载自: Introduction to MPI - Part II (Youtube) Buffering  Suppose we have ) MPI_Send(sendbuf,...,,...) ...

  7. NIO之阻塞IO与非阻塞IO(包含Selector使用)

    阻塞IO 传统的 IO 流都是阻塞式的. 也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务. 因此,在完成网络通信 ...

  8. 【死磕NIO】— 阻塞IO,非阻塞IO,IO复用,信号驱动IO,异步IO,这你真的分的清楚吗?

    通过上篇文章([死磕NIO]- 阻塞.非阻塞.同步.异步,傻傻分不清楚),我想你应该能够区分了什么是阻塞.非阻塞.异步.非异步了,这篇文章我们来彻底弄清楚什么是阻塞IO,非阻塞IO,IO复用,信号驱动 ...

  9. DirectX11 学习笔记9 - 动态顶点缓冲区 和 静态顶点缓冲区

    首先,什么是缓冲区: 缓冲区是.fx文件的影响(.ps .vs还) 一种数据结构,其定义了.为.fx和cpp数据通信文件. 例: //--------------------------------- ...

随机推荐

  1. jmeter bean shell断言加密的响应信息

    断言加密的响应信息 1.在http请求-->添加-->断言-->bean shell 断言 import com.changfu.EncryptAndDecryptInterface ...

  2. luogu P1802 5倍经验日

    题目背景 现在乐斗有活动了!每打一个人可以获得5倍经验!absi2011却无奈的看着那一些比他等级高的好友,想着能否把他们干掉.干掉能拿不少经验的. 题目描述 现在absi2011拿出了x个迷你装药物 ...

  3. NOIP 2015 跳石头

    题目背景 一年一度的“跳石头”比赛又要开始了! 题目描述 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之间,有 N 块岩石(不 ...

  4. [BZOJ4650][NOI2016]优秀的拆分(SAM构建SA)

    关于解法这个讲的很清楚了,主要用了设关键点的巧妙思想. 主要想说的是一个刚学的方法:通过后缀自动机建立后缀树,再转成后缀数组. 后缀数组功能强大,但是最令人头疼的地方是模板太难背容易写错.用这个方法, ...

  5. [Contest20171028]火神的鱼

    火神最爱的就是吃鱼了,所以某一天他来到了一个池塘边捕鱼.池塘可以看成一个二维的平面,而他的渔网可以看成一个与坐标轴平行的矩形.池塘里的鱼不停地在水中游动,可以看成一些点.有的时候会有鱼游进渔网,有的时 ...

  6. 【扩展欧几里得】poj2115 C Looooops

    题意大概是让你求(A+Cx) mod 2^k = B的最小非负整数解. 若(B-A) mod gcd(C,2^k) = 0,就有解,否则无解. 式子可以化成Cx + 2^k*y = B - A,可以用 ...

  7. 【分块】bzoj2724 [Violet 6]蒲公英

    分块,离散化,预处理出: ①前i块中x出现的次数(差分): ②第i块到第j块中的众数是谁,出现了多少次. 询问的时候,对于整块的部分直接获得答案:对于零散的部分,暴力统计每个数出现的次数,加上差分的结 ...

  8. react-native热更新从零到成功中的各种坑

    https://github.com/reactnativecn/react-native-pushy/blob/master/docs/guide.md Android NDK暂时没有安装 在你的项 ...

  9. SpringMVC实现操作的第二种方式

    一: 运行效果: 点击提交之后显示效果 二: (1).web.xml <?xml version="1.0" encoding="UTF-8"?> ...

  10. python 文件操作与集合

    对文件的操作 1.打开文件,获取句柄 2.根据句柄操作文件 3.关闭文件 现有文档 poem.txt 一天很短, 短得来不及拥抱清晨, 就已经手握黄昏. 一年很短, 短得来不及细品初春殷红窦绿, 就要 ...