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

一、非直接缓冲区

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. AtCoder - 2061 Tree Restoring

    Problem Statement Aoki loves numerical sequences and trees. One day, Takahashi gave him an integer s ...

  2. 【最短路】【spfa】小vijos P1447 Updown

    小vijos P1447 Updown 背景 开启了升降梯的动力之后,探险队员们进入了升降梯运行的那条竖直的隧道,映入眼帘的是一条直通塔顶的轨道.一辆停在轨道底部的电梯.和电梯内一杆控制电梯升降的巨大 ...

  3. JavaScript异步编程的Promise模式(转)

    异步模式在web编程中变得越来越重要,对于web主流语言Javascript来说,这种模式实现起来不是很利索,为此,许多Javascript库(比如 jQuery和Dojo)添加了一种称为promis ...

  4. React Native Navigator组件回调

    在push的时候定义回调函数: this.props.navigator.push({ component: nextVC, title: titleName, passProps: { //回调 g ...

  5. iOS开发经验——点击屏幕空白处退出键盘

          一种比较简单的点击屏幕空白处退出键盘的方法: 在ViewController中加入如下代码: 1: -(void)touchesBegan:(NSSet *)touches withEve ...

  6. Intellij IDEA光标保持自动缩进,设置下次不放在行首

  7. 查看Java代码对应的汇编指令又一利器,JITWatch 转

    http://www.tuicool.com/articles/IRrIRb3 时间 2015-05-13 08:00:00  Liuxinglanyue's Blog 原文  http://java ...

  8. Error (10663): Verilog HDL Port Connection error at led_demo.v(6): output or inout port "led" must be connected to a structural net expression

    错误现象:

  9. iOS:IOS项目集成ShareSDK实现第三方登录、分享、关注等功能。

    原文链接:http://blog.csdn.net/daleiwang/article/details/34081231 (3)在项目的AppDelegate中一般情况下有三个操作,第一是注册Shar ...

  10. linux设备驱动:中断的实现

    一.什么是中断 中断分两种: 1)中断,又叫外部中断或异步中断,它的产生是由于外设向处理器发出中断请求.其中外部中断也有两种,这是由配置寄存器设定的:普通中断请求(IRQ)和快速中断请求(FIQ).一 ...