文档章节

JAVA NIO知识点总结(2)——直接缓冲区和非直接缓冲区

HappyBKs
 HappyBKs
发布于 2017/12/19 22:02
字数 1578
阅读 704
收藏 7
NIO

  前面我们一直说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)数据写入物理内存缓冲区中,程序就丧失了对这些数据的管理,即什么时候这些数据被最终写入从磁盘只能由操作系统来决定,应用程序无法再干涉。

 

选择方法

直接缓冲区适合与数据长时间存在于内存,或者大数据量的操作时更加适合

 

 

操作方法

	@Test
	public 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-private

        super(-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 boundary
            address = 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-private

        super(-1, 0, lim, cap, new byte[cap], 0);
        /*
        hb = new byte[cap];
        offset = 0;
        */
    }

 

 

© 著作权归作者所有

HappyBKs

HappyBKs

粉丝 667
博文 306
码字总数 481268
作品 0
浦东
程序员
私信 提问
netty(六) ByteBuf学习.md

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lupeng/article/details/82750051 ByteBuf学习 基于Java Nio的网络通信,必须依赖于ByteBuffer,从程序实际上...

孤落
2018/09/17
0
0
关于Nio的直接与 非直接缓冲区的理解

jdk对nio的ByteBuffer 有allocate 和 allocateDirect 解释为: 字节缓冲区要么是直接的,要么是非直接的。如果为直接字节缓冲区,则 Java 虚拟机会尽最大努力直接在此缓冲区上执行本机 I/O ...

晓残云
2015/06/05
2.4K
3
(代码篇)从基础文件IO说起虚拟内存,内存文件映射,零拷贝

上一篇讲解了基础文件IO的理论发展,这里结合java看看各项理论的具体实现。 传统IO-intsmaze 传统文件IO操作的基础代码如下: FileInputStream in = new FileInputStream("D:\java.txt");in....

intsmaze(刘洋)
2018/08/01
0
0
少啰嗦!一分钟带你读懂Java的NIO和经典IO的区别

本文引用了“架构师社区”公众号的《史上讲的最好的Java NIO与IO的区别与应用》一文部分内容,感谢原作者的技术分享。 1、引言 很多初涉网络编程的程序员,在研究Java NIO(即异步IO)和经典...

JackJiang2011
06/25
0
0
Java NIO:IO与NIO的区别

一、概念 NIO即New IO,这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标...

老菜鸟0217
01/06
25
2

没有更多内容

加载失败,请刷新页面

加载更多

把阿里巴巴的核心系统搬到云上,架构上的挑战与演进是什么?

作者丨张瓅玶(谷朴)阿里巴巴研究员 阿里巴巴核心系统作为全球最大规模、峰值性能要求最高的电商交易系统,在 2018 年之前只通过混合云弹性上云方式,为 双11 节约大量成本。直到 2019 年,...

阿里巴巴云原生
17分钟前
2
0
PHP MySQLi 系列函数

如何用mysqli系列函数连接一个mysql数据库? 1.PHP mysqli_connect()函数:mysqli_connect() 函数打开一个到 MySQL 服务器的新的连接。 语法:mysqli_connect ( host (规定主机名或IP地址), ...

imzchloe
35分钟前
2
0
如何在Notepad ++中格式化XML?

我有Notepad ++ ,我得到了一些非常长的XML代码。 当我将它粘贴在Notepad ++中时,存在很长的代码行(难以阅读和使用)。 我想知道是否有一种简单的方法可以使文本可读(通过可读,我的意思是...

技术盛宴
50分钟前
6
0
(Object[])null

dbutils下QueryRunner.java 的一段代码: package org.apache.commons.dbutils; public <T> T query(Connection conn, String sql, ResultSetHandler<T> rsh) throws SQLException { ......

行者终成事
51分钟前
5
0
商品评价

商品评价 商品评价 商品评价:指买家对所购买商品的评价。 一、商品评价的具体操作:在个人中心找到商品评价,找到商品对其评价,添加评价内容,添加商品图片。 二、商品评价在后台的具体显示...

Geek-Chic
54分钟前
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部