`
caoruntao
  • 浏览: 475935 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

Direct vs non-direct ByteBuffer

    博客分类:
  • java
 
阅读更多

[转]http://littcai.iteye.com/blog/300581

这两种类型的ByteBuffer相信大家都知道,但是两者的区别在什么地方呢?在不同的环境下采用哪种类型的ByteBuffer会更有效率呢?

先解释一下两者的区别:

Non-direct ByteBuffer内存是分配在堆上的,直接由Java虚拟机负责垃圾收集,你可以把它想象成一个字节数组的包装类,如下伪码所示:

HeapByteBuffer extends ByteBuffer {
    byte[] content;
    int position, limit, capacity;
    ......
}

而Direct ByteBuffer是通过JNI在Java虚拟机外的内存中分配了一块(所以即使在运行时通过-Xmx指定了Java虚拟机的最大堆内存,还是可能实例化超出该大小的Direct ByteBuffer),该内存块并不直接由Java虚拟机负责垃圾收集,但是在Direct ByteBuffer包装类被回收时,会通过Java Reference机制来释放该内存块。如下伪码所示:

DirectByteBuffer extends ByteBuffer {
    long address;
    int position, limit, capacity;

    protected void finalize() throws Throwable{
//释放内存块,该段代码仅仅用于演示,真正的Direct ByteBuffer并不是通过finalize来释放的
        releaseAddress();  
        ......
    }
    ......
}

我相信大部分朋友们对上面的区别都应该很了解,那么还有什么其他的区别呢?嘿嘿,让我们稍微深入一点,翻到sun.nio.ch.IOUtil.java,绝大部分Channel类都是通过这个工具类和外界进行通讯的,如FileChannel/SocketChannel等等。我简单的用伪码把write方法给表达出来(read方法也差不多,就不多做说明了)

int write(ByteBuffer src, ......) {
    if (src instanceof DirectBuffer)
        return writeFromNativeBuffer(...);
    ByteBuffer direct = getTemporaryDirectBuffer(src);
    writeFromNativeBuffer(direct,......);
    updatePosition(src);
    releaseTemporaryDirectBuffer(direct);
}

是的,在发送和接收前会把Non-direct ByteBuffer转换为Direct ByteBuffer,然后再进行相关的操作,最后更新原始ByteBuffer的position。这意味着什么?假设我们要从网络中读入一段数据,再把这段数据发送出去的话,采用Non-direct ByteBuffer的流程是这样的:

 网络 --> 临时的Direct ByteBuffer --> 应用 Non-direct ByteBuffer --> 临时的Direct ByteBuffer --> 网络

而采用Direct ByteBuffer的流程是这样的:

网络 --> 应用 Direct ByteBuffer --> 网络

可以看到,除开构造和析构临时Direct ByteBuffer的时间外,起码还能节约两次内存拷贝的时间。那么是否在任何情况下都采用Direct Buffer呢?

不是。对于大部分应用而言,两次内存拷贝的时间几乎可以忽略不计,而构造和析构Direct Buffer的时间却相对较长。在JVM的实现当中,某些方法会缓存一部分临时Direct ByteBuffer,意味着如果采用Direct ByteBuffer仅仅能节约掉两次内存拷贝的时间,而无法节约构造和析构的时间。就用Sun的实现来说,write(ByteBuffer)和read(ByteBuffer)方法都会缓存临时Direct ByteBuffer,而write(ByteBuffer[])和read(ByteBuffer[])每次都生成新的临时Direct ByteBuffer。

根据这些区别,我会提出如下的建议:

  • 如果你做中小规模的应用(在这里,应用大小是按照使用ByteBuffer的次数和规模来做划分的),而且并不在乎这该死的细节问题,请选择Non-direct ByteBuffer
  • 如果采用Direct ByteBuffer后性能并没有出现你所期待的变化,请选择Non-direct ByteBuffer
  • 如果没有Direct ByteBuffer Pool,尽量不要使用Direct ByteBuffer
  • 除非你确定该ByteBuffer会长时间存在,并且和外界有频繁交互,可采用Direct ByteBuffer
  • 如果采用Non-direct ByteBuffer,那么采用非聚集(gather)的write/read(ByteBuffer)效果反而可能超出聚集的write/read(ByteBuffer[]),因为聚集的write/read的临时Direct ByteBuffer是非缓存的

基本上,采用Non-direct ByteBuffer总是对的!因为内存拷贝需要的开销对大部分应用而言都可以忽略不计。不过我做的是大规模的网络并发框架,因此对这些细节问题还是有必要有深入认识的,并且根据这些细节来调节自己的Buffer继承体系(再次抱怨,ByteBuffer无法扩展实在是一个非常非常非常费解的设计)

 

注:前面提到的“即使在运行时通过-Xmx指定了Java虚拟机的最大堆内存,还是可能实例化超出该大小的Direct ByteBuffer”中的可能是指可以通过-XX:MaxDirectMemorySize=<size>来指定Direct ByteBuffer实例最多可以使用的内存总数。如指定-XX:MaxDirectMemorySize=1024,则系统中所有存活的Direct ByteBuffer总内存数不能超过1024字节。

分享到:
评论

相关推荐

    JAVA IO-NIO 详解

    - **Direct vs Non-Direct Buffer**: Direct Buffer直接映射到物理内存,Non-Direct Buffer在JVM堆上分配内存。 **3. Buffer的日常操作** - **put**: 向Buffer写入数据。 - **get**: 从Buffer读取数据。 - **flip*...

    Java-NIO-Programming-Cookbook(含源码)

    `DirectByteBuffer`是`ByteBuffer`的一个实现,它与`Non-Direct Buffer`(即堆缓冲区)有所不同。直接缓冲区在Java中使用JNI(Java Native Interface)直接在物理内存中分配,而不需要经过Java堆,这通常能提高性能...

    07-Netty面试题(最新版).zip

    - **NIO (Non-blocking I/O)**:Netty基于Java NIO API构建,实现了非阻塞I/O模型,使得在高并发场景下,性能显著优于传统的BIO。 - **Channel**:Netty中的核心概念,代表网络连接,如TCP连接或UDP套接字。 - **...

    Java中的缓冲区(直接缓冲区、非直接缓冲区等).docx

    缓冲区主要分为直接缓冲区(Direct Buffer)和非直接缓冲区(Non-Direct Buffer)。这两种缓冲区的区别在于它们如何与底层操作系统交互以及内存的分配方式。 1. **直接缓冲区**: 直接缓冲区是在Java虚拟机外部,...

    【面试资料】-(机构内训资料)Netty面试题.zip

    - **NIO (Non-blocking I/O)**:Netty基于Java NIO API构建,实现了非阻塞I/O模型,使得在高并发环境下,系统资源得以高效利用。 - **Channel**:Netty中的Channel是连接到某个特定I/O服务的抽象,如TCP连接、UDP...

    netty-code源码

    1. **NIO (非阻塞I/O)**:Netty基于Java NIO(Non-blocking I/O)构建,它允许在单个线程中处理多个连接,从而提高了系统的并发性能。 2. **Channel**:Netty中的Channel是网络连接的抽象,它可以是TCP连接、UDP...

    netty-4.1.19.Final

    1. **异步事件驱动**:Netty 使用非阻塞I/O模型,基于Java NIO(Non-blocking I/O)库,通过EventLoop和Channel事件模型,实现了高效的并发处理,能够处理大量并发连接。 2. **高度可定制的API**:Netty 提供了灵活...

    netty-all-5.0.0.Alpha2

    1. **NIO(非阻塞I/O)**: Netty基于Java NIO (Non-blocking I/O) 构建,提供了更高效的I/O操作。NIO允许单线程处理多个通道(Channel),从而减少了线程切换的开销,提高了系统资源利用率。 2. **ByteBuf**: Netty...

    Netty面试专题.zip

    - **NIO(Non-blocking I/O)**:Netty是基于Java NIO构建的,它允许在一个线程中处理多个连接,提高了系统的并发性。 - **Channel**:Netty中的I/O操作都是通过Channel进行的,它是连接的抽象,可以是TCP连接、...

    netty-4.1 源码包

    1. **NIO (Non-blocking I/O)**: Netty 使用Java NIO API,提供了非阻塞的I/O操作,使得系统能处理大量并发连接,尤其适合高负载、高并发的网络服务。 2. **Channel**: Channel是Netty中的核心概念,代表一个到另...

    netty权威指南(第二版)

    《Netty权威指南》是Java领域中关于网络编程的一本重要参考书籍,尤其在第二版中,它深入探讨了非阻塞I/O(NIO,Non-blocking I/O)技术,这是Java开发高并发、高性能网络应用的核心技术。Netty是一个开源的异步事件...

    最新JDK教程(CHM版)

    ##### 1.3 非阻塞I/O(NON-BLOCKING)和多路I/O(MULTIPLEXED) - **概念**:传统的阻塞式I/O会阻塞线程,而新的非阻塞式I/O可以在没有数据可读或写时返回,从而提高效率。 - **多路I/O**:通过`Selector`和`...

    自动netty笔记111

    Netty采用了非阻塞I/O模型,基于Java NIO(Non-blocking I/O)库,允许在单个线程中处理多个连接,提高了系统的并发能力。这种模型通过EventLoop(事件循环)和ChannelHandler(通道处理器)来处理网络事件,如连接...

    经典算法导论

    - **直接缓冲器(DirectBuffer)**:直接在堆外内存中分配缓冲区,减少垃圾回收的影响,提高性能。 - **特点**:直接缓冲器不会被JVM垃圾回收器管理,因此适用于大量数据传输的情况。 - **使用**:通过`ByteBuffer....

    Netty 教程 Netty权威指南

    1. **NIO(非阻塞I/O)基础**:Netty 基于 Java NIO (Non-blocking I/O) 构建,提供了更高效的 I/O 处理方式,通过 Channel 和 Selector 实现多路复用,可以同时处理大量并发连接。 2. **ByteBuf**:Netty 提供了 ...

    Netty_Learn:Nettty源码阅读

    - Netty的核心是基于非阻塞I/O模型,利用Java的NIO(Non-blocking I/O)API,实现了高并发和低延迟的网络服务。 2. **Netty的主要组件** - **ByteBuf**: Netty自定义的缓冲区,优于Java的ByteBuffer,提供了更...

Global site tag (gtag.js) - Google Analytics