JAVA NIO知识点总结(2)——直接缓冲区和非直接缓冲区
2019独角兽企业重金招聘Python工程师标准>>>
前面我们一直说NIO能够提高性能,那么到底如何提高效率。本篇就接着上一篇文章的缓冲区,来看看直接缓冲区和非直接缓冲区。
非直接缓冲区
首先看看非直接缓冲区。我们之前说过NIO通过通道连接磁盘文件与应用程序,通过缓冲区存取数据进行双向的数据传输。物理磁盘的存取是操作系统进行管理的,与物理磁盘的数据操作需要经过内核地址空间;而我们的Java应用程序是通过JVM分配的缓冲空间。有点雷同于一个属于核心态,一个属于应用态的意思,而数据需要在内核地址空间和用户地址空间,在操作系统和JVM之间进行数据的来回拷贝,无形中增加的中间环节使得效率与后面要提的之间缓冲区相比偏低。
直接缓冲区
直接缓冲区则不再通过内核地址空间和用户地址空间的缓存数据的复制传递,而是在物理内存中申请了一块空间,这块空间映射到内核地址空间和用户地址空间,应用程序与磁盘之间的数据存取之间通过这块直接申请的物理内存进行。
直接与非直接缓冲区的要点
字节缓冲区要么是直接的,要么是非直接的。如果为直接字节缓冲区,则 Java 虚拟机会尽最大努力直接在此缓冲区上执行本机 I/O 操作。也就是说,在每次调用操作系统基础的一个本机 I/O 操作之前(或之后),虚拟机都会尽量避免将缓冲区的内容复制到中间缓冲区中(或从中间缓冲区中复制内容)。
直接字节缓冲区可以通过调用此类的 allocateDirect() 工厂方法来创建。此方法返回的缓冲区进行分配和取消分配所需成本通常高于非直接缓冲区。直接缓冲区的内容可以驻留在常规的垃圾回收堆之外,因此,它们对应用程序的内存需求量造成的影响可能并不明显。所以,建议将直接缓冲区主要分配给那些易受基础系统的本机 I/O 操作影响的大型、持久的缓冲区。一般情况下,最好仅在 直接缓冲区能在程序性能方面带来明显好处时 分配它们。
直接字节缓冲区还可以通过 FileChannel 的 map() 方法 将文件区域直接映射到内存中来创建。该方法返回MappedByteBuffer 。 Java 平台的实现有助于通过 JNI 从本机代码创建直接字节缓冲区。如果以上这些缓冲区中的某个缓冲区实例指的是不可访问的内存区域,则试图访问该区域不会更改该缓冲区的内容,并且将会在访问期间或稍后的某个时间导致抛出不确定的异常。
字节缓冲区是直接缓冲区还是非直接缓冲区可通过调用其 isDirect() 方法来确定。提供此方法是为了能够在性能关键型代码中执行显式缓冲区管理
(本文出自oschina博主happyBKs的博文:https://my.oschina.net/happyBKs/blog/1592329)
那么既然直接缓冲区的性能更高、效率更快,为什么还要存在两种缓冲区呢?因为直接缓冲区也存在着一些缺点:
(1)不安全
(2)消耗更多,因为它不是在JVM中直接开辟空间。这部分内存的回收只能依赖于垃圾回收机制,垃圾什么时候回收不受我们控制。
(3)数据写入物理内存缓冲区中,程序就丧失了对这些数据的管理,即什么时候这些数据被最终写入从磁盘只能由操作系统来决定,应用程序无法再干涉。
选择方法
直接缓冲区适合与数据长时间存在于内存,或者大数据量的操作时更加适合
操作方法
@Testpublic void test3(){ByteBuffer dirBuf = ByteBuffer.allocateDirect(1024);if(dirBuf.isDirect()){System.out.println("dirBuf 是直接缓冲区");}else{System.out.println("dirBuf 是非直接缓冲区");}}
这是第一种建立直接缓冲区的方法。
之后我们介绍了通道之后,我们就有了第二种建立直接缓冲区的方式——建立内存映射文件,来建立直接缓冲区。
源码简析
我们可以看看直接缓冲区申请的源码:
/*** Allocates a new direct byte buffer.** <p> The new buffer's position will be zero, its limit will be its* capacity, its mark will be undefined, and each of its elements will be* initialized to zero. Whether or not it has a* {@link #hasArray backing array} is unspecified.** @param capacity* The new buffer's capacity, in bytes** @return The new byte buffer** @throws IllegalArgumentException* If the <tt>capacity</tt> is a negative integer*/public static ByteBuffer allocateDirect(int capacity) {return new DirectByteBuffer(capacity);}
我们再看DirectByteBuffer的构造实现:
// Primary constructor//DirectByteBuffer(int cap) { // package-privatesuper(-1, 0, cap, cap);boolean pa = VM.isDirectMemoryPageAligned();int ps = Bits.pageSize();long size = Math.max(1L, (long)cap + (pa ? ps : 0));Bits.reserveMemory(size, cap);long base = 0;try {base = unsafe.allocateMemory(size);} catch (OutOfMemoryError x) {Bits.unreserveMemory(size, cap);throw x;}unsafe.setMemory(base, size, (byte) 0);if (pa && (base % ps != 0)) {// Round up to page boundaryaddress = base + ps - (base & (ps - 1));} else {address = base;}cleaner = Cleaner.create(this, new Deallocator(base, size, cap));att = null;}
可以看到unsafe.allocateMemory(size);已经不能进入源码了,它已经是操作系统层面的jni调用了。
我们再看看非直接缓冲区的申请源码:
它申请的是堆空间,即在JVM上的操作。
/*** Allocates a new byte buffer.** <p> The new buffer's position will be zero, its limit will be its* capacity, its mark will be undefined, and each of its elements will be* initialized to zero. It will have a {@link #array backing array},* and its {@link #arrayOffset array offset} will be zero.** @param capacity* The new buffer's capacity, in bytes** @return The new byte buffer** @throws IllegalArgumentException* If the <tt>capacity</tt> is a negative integer*/public static ByteBuffer allocate(int capacity) {if (capacity < 0)throw new IllegalArgumentException();return new HeapByteBuffer(capacity, capacity);}
再进一层,我们已经可以看到byte数组了。
HeapByteBuffer(int cap, int lim) { // package-privatesuper(-1, 0, lim, cap, new byte[cap], 0);/*hb = new byte[cap];offset = 0;*/}
转载于:https://my.oschina.net/happyBKs/blog/1592329
JAVA NIO知识点总结(2)——直接缓冲区和非直接缓冲区相关推荐
- Java-NIO(三):直接缓冲区与非直接缓冲区
直接缓冲区与非直接缓冲区的概念: 1)非直接缓冲区:通过 static ByteBuffer allocate(int capacity) 创建的缓冲区,在JVM中内存中创建,在每次调用基础操作系统的 ...
- Java NIO学习篇之直接缓冲区和非直接缓冲区
定义 以上是书深入理解java虚拟机对直接内存的描述.直接缓冲区用的就是直接内存. java nio字节缓冲区要么是直接的,要么是非直接的.如果为直接字节缓冲区,则java虚拟机会尽最大努力直接在此缓 ...
- Java NIO之 直接缓冲区与非直接缓冲区
非直接缓冲区:通过allocate()方法分配缓冲区,将缓冲区建立在JVM的内存中. 直接缓冲区:通过allocateDirect()方法分配直接缓冲区,将缓冲区建立在物理内存中.可以提高效率. 字节 ...
- java 文件缓冲区_基于直接缓冲区和非直接缓冲区的javaIO文件操作
基本概念: 1. 非直接缓冲区: 指的是通过jvm来缓存数据的,应用程序要读取本地数据要经历从本地磁盘到物理内存,然后copy到jvm中,然后再通过流的方式读取到应用程序中,写的操作正好与之相反. ...
- Java NIO ———— Buffer 缓冲区详解
引言 缓冲区是一个用于特定基本类型的容器.由java.nio 包定义,所有缓冲区都是 Buffer 抽象类的子类. Java NIO 中的 Buffer ,主要用于与NIO 通道进行交互.数据从通道存 ...
- Java NIO基础之缓冲区buffer(笔记 day01)
学习笔记,仅供参考,禁止搬运,如有不正确的地方欢迎大家指正,谢谢!!! 一.缓冲区buffer 代码 package com.lihefei.nio.day01; import org.junit. ...
- 【Java NIO】一文了解NIO
[Java NIO]一文了解NIO Java NIO 1 背景介绍 在上一篇文章中我们介绍了Java基本IO,也就是阻塞式IO(BIO),在JDK1.4版本后推出了新的IO系统(NIO),也可以理解为 ...
- java nio is例子,Java Buffer isDirect()用法及代码示例
java.nio.Buffer类的isDirect()方法用于判断此缓冲区是否是直接缓冲区. 用法: public abstract boolean isDirect() 返回值:当且仅当此缓冲区是直 ...
- Java NIO SocketChannel+Buffer+Selector 详解(含多人聊天室实例)
一.Java NIO 的核心组件 Java NIO的核心组件包括:Channel(通道),Buffer(缓冲区),Selector(选择器),其中Channel和Buffer比较好理解 简单来说 N ...
最新文章
- 那些年,面试被虐过的红黑树
- 如何将传统OA移动化?
- Several ports (8005, 8080, 8009) required by Tomcat v5.5 Server at localhost are already in use.....
- 静态程序分析chapter2 - IR(Jimple) 和 CFG
- ASP.NET2.0中的ClientScriptManager 类用法—如何添加客户端事件
- ibatis annotations 注解方式返回刚插入的自增长主键ID的值--转
- 单词背诵【CodeVS3013】 哈希
- BaseExecutor.query()-创建CacheKey
- MFC Windows编程模型
- c语言电子地图程序,C语言 电子地图信息
- CoreData学习-最好的一片文章
- Camtasia Recorder 2020如何确定录制区域
- mysql批量插入之提高插入效率
- 清华大学中国人工智能学会:2019人工智能发展报告
- springMVC自定义类型转换器(字符串String转日期Date)
- rdkit Kekulize
- python降序_Python中numpy如何进行降序?
- 项立刚:国外品牌很可能输掉3G手机这一战役
- AI实战:上海垃圾分类系列(一)之快速搭建垃圾分类模型
- AD画原理图保留十字节点
热门文章
- html5media使用
- 从编译安装Keepalived 到 配置 负载均衡(LVS-DR)
- 数据结构之---二叉树C实现
- Fiddler 跟踪数据包
- 不可摸数http://acm.hdu.edu.cn/showproblem.php?pid=1999
- STATISTICS TIME ON
- 使用GridView做出列选择效果(获取动态生成的控件.鼠标点选GridView.Ajax控件)
- 介绍Cassandra中的压缩
- php string pos,有关pos()的文章推荐10篇
- RabbitMQ发布确认原理