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

直接缓冲区:内核地址空间和用户地址空间之间形成了一个物理内存映射文件,减少了之间的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之直接缓冲区与非直接缓冲区的更多相关文章
- Java NIO -- 直接缓冲区与非直接缓冲区
直接缓冲区与非直接缓冲区: 非直接缓冲区:通过 allocate() 方法分配缓冲区,将缓冲区建立在 JVM 的内存中直接缓冲区:通过 allocateDirect() 方法分配直接缓冲区,将缓冲区建 ...
- Java-NIO(三):直接缓冲区与非直接缓冲区
直接缓冲区与非直接缓冲区的概念: 1)非直接缓冲区:通过 static ByteBuffer allocate(int capacity) 创建的缓冲区,在JVM中内存中创建,在每次调用基础操作系统的 ...
- 基于直接缓冲区和非直接缓冲区的javaIO文件操作
基本概念: 1. 非直接缓冲区: 指的是通过jvm来缓存数据的,应用程序要读取本地数据要经历从本地磁盘到物理内存,然后copy到jvm中,然后再通过流的方式读取到应用程序中,写的操作正好与之相反. ...
- java NIO 直接与非直接缓冲区
ByteBuffer有两个创建缓冲区的方法:static ByteBuffer allocate(int capacity)static ByteBuffer allocateDirect(int c ...
- 使用非直接缓冲区与直接缓冲区进行文件的复制(基于Channel)
一.利用通道完成文件的复制(非直接缓冲区) long start = System.currentTimeMillis(); FileInputStream fis = new FileInp ...
- MPI - 缓冲区和非阻塞通信
转载自: Introduction to MPI - Part II (Youtube) Buffering Suppose we have ) MPI_Send(sendbuf,...,,...) ...
- NIO之阻塞IO与非阻塞IO(包含Selector使用)
阻塞IO 传统的 IO 流都是阻塞式的. 也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务. 因此,在完成网络通信 ...
- 【死磕NIO】— 阻塞IO,非阻塞IO,IO复用,信号驱动IO,异步IO,这你真的分的清楚吗?
通过上篇文章([死磕NIO]- 阻塞.非阻塞.同步.异步,傻傻分不清楚),我想你应该能够区分了什么是阻塞.非阻塞.异步.非异步了,这篇文章我们来彻底弄清楚什么是阻塞IO,非阻塞IO,IO复用,信号驱动 ...
- DirectX11 学习笔记9 - 动态顶点缓冲区 和 静态顶点缓冲区
首先,什么是缓冲区: 缓冲区是.fx文件的影响(.ps .vs还) 一种数据结构,其定义了.为.fx和cpp数据通信文件. 例: //--------------------------------- ...
随机推荐
- hdu6071(最短路)
hdu6071 题意 四个点连接形成一个环,给出相邻两个点的距离,求从点 \(2\) 出发再回到 \(2\) 的路程大于等于 \(K\) 的最小值. 分析 首先我们让 \(w=min(d12, d23 ...
- 线段树 (区间合并)【p2894】[USACO08FEB]酒店Hotel
Descripion 奶牛们最近的旅游计划,是到苏必利尔湖畔,享受那里的湖光山色,以及明媚的阳光.作为整个旅游的策划者和负责人,贝茜选择在湖边的一家著名的旅馆住宿.这个巨大的旅馆一共有N (1 < ...
- 简单DP【p3399】丝绸之路
Background 张骞于公元前138年曾历尽艰险出使过西域.加强了汉朝与西域各国的友好往来.从那以后,一队队骆驼商队在这漫长的商贸大道上行进,他们越过崇山峻岭,将中国的先进技术带向中亚.西亚和欧洲 ...
- Linux命令之groupadd
groupadd [选项] 组 创建一个新的组.Groupadd命令使用命令行中指定的值加上系统默认值创建新的组账户.新组将根据需要输入系统. (1).选项 -f,--force 如果指定的组已经存在 ...
- ASP.NET Core 2.2 基础知识(四) URL重写中间件
说到URL重写就不得不提URL重定向. URL重定向 URL重定向是客户端操作,指示客户端访问另一个地址的资源.这需要往返服务器,并且当客户端对资源发出请求时,返回客户端的重定向URL会出现在浏览器的 ...
- CodeForces - 981E Addition on Segments
考虑每个点i在什么情况下会成为最大值. 当选的区间子集是 包含i的区间的一个子集的时候,i肯定会是最大值. 所以我们就可以用这种方法得到所有点的可能的最大值是多少... 也就是说,最后的局面可以仅由一 ...
- [Contest20180316]Mythological IV
令$S(n)=\sum\limits_{i=0}^{n-1}f(i)q^i$,那么存在一个次数$\leq k$的多项式使得$S(n)=q^ng(n)-g(0)$(证明来自杜教的PPT) 设$f$的次数 ...
- 【R笔记】日期处理
R语言学习笔记:日期处理 1.取出当前日期 Sys.Date() [1] "2014-10-29" date() #注意:这种方法返回的是字符串类型 [1] "Wed O ...
- Ubuntu 14 下,命令行终端显示短路径
Ubuntu的终端命令行默认是长路径,即把路径深度全部显示出来,操作起来不是很方便,下面介绍命令行显示短路径的操作: $ vi ~/.bashrc 找到PS1= 的行,将\w(小写)改成\W(大写 ...
- [转]Nginx调用远程php-fpm
Nginx调用远程php-fpm 前后端分离的网站,要在异地部署多套网页的时候,这种nginx配置调用远程php-fpm的方式,不错.可以提高网页的相应速度. 原文: https://www.cnbl ...