转载-Non-direct与direct ByteBuffer区别

转载 2012年03月29日 15:52:40
 
 

转载于:http://crmky.spaces.live.com/Blog/cns!8C989768DB1A6B14!458.entry?sa=254330365这两种类型的ByteBuffer相信大家都知道,但是两者的区别在什么地方呢?在不同的环境下采用哪种类型的ByteBuffer会更有效率呢?

先解释一下两者的区别:

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

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

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

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

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

        releaseAddress();  
        ......
    }
    ......
}

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

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

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

 网络 --> 临时的DirectByteBuffer --> 应用 Non-directByteBuffer --> 临时的DirectByteBuffer --> 网络

而采用DirectByteBuffer的流程是这样的:

网络 --> 应用 DirectByteBuffer --> 网络

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

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

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

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

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

 

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

相关文章推荐

android----在JNI中如何使用ByteBuffer?

1,ByteBuffer 定义 在NIO中,数据的读写操作始终是与缓冲区相关联的(读取时信道(SocketChannel)将数据读入缓冲区,写入时首先要将发送的数据按顺序填入缓冲区) 缓冲区是...

《Java源码解析》NIO中的heap Buffer和direct Buffer区别

heap buffer 和 direct buffer区别在Java的NIO中,我们一般采用ByteBuffer缓冲区来传输数据,一般情况下我们创建Buffer对象是通过ByteBuffer的两个静态...

【Java8源码分析】NIO包-Buffer类:内存映射文件DirectByteBuffer与MappedByteBuffer(二)

转载请注明出处:http://blog.csdn.net/linxdcn/article/details/72896616
  • linxdcn
  • linxdcn
  • 2017年06月08日 21:16
  • 931

Android开发实践:Java层与Jni层的数组传递

Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是Java层把需要发送给客户端的数据流传递到Jni层,由Jni层的Socket代码发送出去,当然,Jni...

java之HeapByteBuffer&DirectByteBuffer以及回收DirectByteBuffer

byte buffer一般在网络交互过程中java使用得比较多,尤其是以NIO的框架中; 看名字就知道是以字节码作为缓冲的,先buffer一段,然后flush到终端。 而本文要说的一个重点就是He...
  • xieyuooo
  • xieyuooo
  • 2012年05月08日 20:12
  • 17032

NIO DirectByteBuffer深入理解

1. 基础知识    1.1 网络通信内存空间模型         1)非直接内存方式时,数据需要在如下空间进行复制,              JVM Heap JVM用户空间 OS内...
  • Jinuxwu
  • Jinuxwu
  • 2015年12月10日 17:28
  • 1865

堆外内存DirectByteBuffer剖析

操作系统中除了jvm申请的内存外,还有一块jvm以外的内存,这块内存空间一船是连续的,DirectByteBuffer对象是在jvm申请和创建的,内容是在堆外内存存放的的,DirectByteBuff...

DirectByteBuffer内存申请与释放

DirectByteBuffer类是在Java Heap外分配内存,对堆外内存的申请主要是通过成员变量unsafe来操作,下面介绍构造方法     // Primary constructo...

System.gc()和-XX:+DisableExplicitGC启动参数,以及DirectByteBuffer的内存释放

我们知道java代码无法强制JVM何时进行垃圾回收,也就是说垃圾回收这个动作的触发,完全由JVM自己控制,它会挑选合适的时机回收堆内存中的无用java对象。代码中显示调用System.gc(),只是建...

Java NIO学习笔记之二-图解ByteBuffer

目录:[ - ] 概述使用ByteBuffer内部字段byte[] buffpositionmarkcapacitylimit图解putflipgetclear ByteBuffer前前后后看过...
  • Baple
  • Baple
  • 2013年10月15日 14:01
  • 23480
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:转载-Non-direct与direct ByteBuffer区别
举报原因:
原因补充:

(最多只允许输入30个字)