`
leonzhx
  • 浏览: 793318 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Zz Direct vs non-direct ByteBuffer

    博客分类:
  • Java
阅读更多

先解释一下两者的区别:

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

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

Direct ByteBuffer是通过JNIJava虚拟机外的内存中分配了一块(所以即使在运行时通过-Xmx指定了Java虚拟机的最大堆内存,还是可能实例化超出该大小的DirectByteBuffer),该内存块并不直接由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,然后再进行相关的操作,最后更新原始ByteBufferposition。这意味着什么?假设我们要从网络中读入一段数据,再把这段数据发送出去的话,采用Non-direct ByteBuffer的流程是这样的:

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

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

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

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

不是。对于大部分应用而言,两次内存拷贝的时间几乎可以忽略不计,而构造和析构Direct Buffer的时间却相对较长。在JVM的实现当中,某些方法会缓存一部分临时DirectByteBuffer,意味着如果采用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字节。

分享到:
评论

相关推荐

    dena-bytebuffer:dena-bytebuffer

    《深入解析dena-bytebuffer:JavaScript中的高效二进制数据处理》 在JavaScript的世界里,处理二进制数据是一项常见的任务,特别是在网络通信、游戏开发、图像处理等领域。`dena-bytebuffer`库就是为了解决这个问题...

    【IT十八掌徐培成】Java基础第26天-05.ByteBuffer-mark-pos-limit-cap-flip.zip

    在Java编程语言中,`ByteBuffer`是Java NIO(New IO)框架中的核心类之一,它提供了一种高效处理字节数据的方式。本教程重点讲解了`ByteBuffer`的几个关键属性:mark、position、limit和capacity,以及重要的操作...

    ios-byteBuffer:在objective-c中重写一个类

    ios-byteBuffer [![CI状态]( Lee / ios-byteBuffer.svg?style = flat)]( Lee / ios-byteBuffer ) 用法 #分配 ByteBuffer *buffer = [ByteBuffer initWithOrder: ByteOrderLittleEndian]; #输入数据 - ( ...

    互联网大厂Netty网络编程开发三部曲-Netty优化+进阶+ 入门 Netty协议设计与解析

    ├─(5) 第1章_05_bytebuffer-基本使用.mp4 ├─(6) 第1章_06_bytebuffer-内部结构.mp4 ├─(7) 第1章_07_bytebuffer-方法演示1.mp4 ├─(8) 第1章_08_bytebuffer-方法演示2.mp4 ├─(9) 第1章_09_bytebuffer-方法...

    深入理解Apache Mina (6)---- Java Nio ByteBuffer与Mina ByteBuffer的区别

    本篇将深入探讨Java NIO(非阻塞I/O)中的ByteBuffer和Mina库自定义的ByteBuffer之间的区别。 Java NIO的ByteBuffer是Java标准库提供的一个核心类,它是通道(Channel)和缓冲区(Buffer)之间数据传输的主要媒介。它...

    Android中的ByteBuffer解析

    ByteBuffer是Java NIO(Non-Blocking I/O)的一部分,允许开发者高效地读写大量原始字节,如处理图像、音频或网络数据。本文将深入探讨Android中ByteBuffer的工作原理及其常见应用场景。 一、ByteBuffer的基础概念 ...

    ByteBuffer-scanner-Memor-Hex:出色地

    标题中的“ByteBuffer-scanner-Memor-Hex”很可能是一个关于Java编程中的内存处理和数据解析的项目或库。ByteBuffer是Java标准库中的一个关键类,主要用于处理二进制数据,尤其是在网络通信、文件读写以及内存操作等...

    grpc头文件和库VS2015-win32_x64-Debug(MDd)_Release(MD).rar

    例如,`grpc/grpc.h`包含gRPC的基础定义,`grpcpp/impl/codegen/service_type.h`定义了服务类型,而`grpcpp/support/byte_buffer.h`则提供了处理ByteBuffer的工具。 使用这些文件,开发者可以在Windows平台上,无论...

    ByteBuffer.zip

    在IT行业中,ByteBuffer是一个非常重要的概念,特别是在网络通信和数据处理领域。ByteBuffer是Java平台提供的一种高效的数据操作接口,它允许我们以字节为单位进行读写操作,这对于处理二进制数据尤其有用。在...

    protobuf+long+bytebuffer

    从网络或者存储中获取到protobuf编码的二进制数据后,可以创建一个`ByteBuffer`实例,然后调用protobuf编译器生成的类的解析方法,传入`ByteBuffer`实例进行解码。`ByteBuffer`会根据protobuf编码规则正确地读取和...

    Java NIO学习笔记——ByteBuffer用法

    本文主要关注的是Java NIO中的ByteBuffer,一个关键的数据容器,用于在通道(Channel)和缓冲区(Buffer)之间传输数据。ByteBuffer的用法是Java NIO学习中的核心内容。 首先,我们了解下ByteBuffer的基本概念。...

    易语言汇编版ByteBuffer-易语言

    http://docs.oracle.com/javase/6/docs/api/java/nio/ByteBuffer.html 主要用于各种网络协议的组包具体用法可以点上面的网址功能和jAVA的一样

    NIO(byteBuffer)按行读取文件

    使用nio byteBuffer 实现按行读取文件(大文件) 在window/linux/macOS上均测试通过 对于中文乱码也已处理成功 完整注释,可随需求更改 有问题请邮件:mly610865580@126.com

    易语言-易语言汇编版ByteBuffer

    在易语言中,“易语言汇编版ByteBuffer”是一个针对网络通信协议处理的重要组件。ByteBuffer的设计灵感来源于Java语言中的同名类,它的主要功能是用于在网络协议的打包和解包过程中处理二进制数据。 ByteBuffer的...

    JAVA IO-NIO 详解

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

    jdk api-ServerSocketChannel、Selector、ByteBuffer结合实现网络报文间的通讯

    jdk api-ServerSocketChannel、Selector、ByteBuffer结合实现网络报文间的通讯

    ByteBuffer.cs

    主要解决从流中获取数据,缓存,拆解,可用于TCP粘包问题

    Android在JNI中使用ByteBuffer的方法

    ByteBuffer作为一个关键的类,它在NIO(New IO)包中,提供了对内存块的直接访问,使得在JNI中进行数据传输更为高效。下面将详细介绍在Android JNI中使用ByteBuffer的方法及其相关知识点。 首先,了解ByteBuffer的...

    易语言汇编版ByteBuffer源码

    易语言汇编版ByteBuffer源码是一个专为易语言平台设计的、用于处理网络协议数据的模块。在IT领域,ByteBuffer通常被用作一个高效的缓冲区,它可以存储和操作字节序列,尤其在处理网络通信时,能有效地组织和传输数据...

Global site tag (gtag.js) - Google Analytics