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

一、非直接缓冲区

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. while(scanf("%d",&n)!=EOF)

    scanf的返回值由后面的参数决定 scanf("%d%d", &a, &b); 如果a和b都被成功读入,那么scanf的返回值就是2 如果只有a被成功读入,返回值 ...

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

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

  3. Android的日志工具Log

    Android中的日志工具类是Log(android.util.Log),这个类提供了以下几个方法来供我们打印日志. ♦ Log.v():这个方法用于打印那些最为琐碎的,意义最小的日志信息.对应级别v ...

  4. [BZOJ 2752] 高速公路

    Link: BZOJ 2752 传送门 Solution: 虽然有期望,但实际上就是除了个总数…… 此题计算总代价明显还是要使用对每个$w_i$计算贡献的方式: $w_i的贡献为w_i*(i-l+1) ...

  5. [BZOJ 1801] Chess

    Link: BZOJ 1801 传送门 Solution: 一眼看过去又像是状压$dp$的经典模型…… 但此题$n,m\le 100$ ,直接跑状压只有50分 此时要发现这道题的特点:每行/列不能放置 ...

  6. 【递归】先修课 计算概论(A) / 函数递归练习(3)2:分解因数

    #include<cstdio> using namespace std; bool is_prime(int x) { ;i*i<=x;i++) ) return false; r ...

  7. 【点分治】hdu5016 Mart Master II

    点分治好题. ①手动开栈. ②dp预处理每个点被哪个市场控制,及其距离是多少,记作pair<int,int>数组p. ③设dis[u].first为u到重心s的距离,dis[u].seco ...

  8. 前端基础-HTML标记语言

    阅读目录 一. HTML标签与文档结构 二. HTML标签详细语法与注意点 三. HTML中标签分类 四. HTML注释 一. HTML标签与文档结构 HTML作为一门标记语言,是通过各种各样的标签来 ...

  9. Spring IOC 中三种注入方式

    项目错误知识点记录 正文 最近在项目的时候,用到Spring框架,Spring框架提供了一种IOC的自动注入功能,可以很轻松的帮助我们创建一个Bean,这样就省的我们四处写new Object()这样 ...

  10. iOS开发——给ImageView添加点击事件

          给ImageView添加点击事件   1: cell.pictureView.userInteractionEnabled = YES; 2: UITapGestureRecognizer ...