作者:Grey

原文地址:Java IO学习笔记二:DirectByteBuffer与HeapByteBuffer

ByteBuffer.allocate()与ByteBuffer.allocateDirect()的基本使用

这两个API封装了一个统一的ByteBuffer返回值,在使用上是无差别的。

import java.nio.ByteBuffer;

public class TestByteBuffer {
    public static void main(String[] args) {
        ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
        System.out.println("position: " + buffer.position());
        System.out.println("limit: " + buffer.limit());
        System.out.println("capacity: " + buffer.capacity());
        System.out.println("mark: " + buffer);

        buffer.put("123".getBytes());

        System.out.println("-------------put:123......");
        System.out.println("mark: " + buffer);

        buffer.flip();

        System.out.println("-------------flip......");
        System.out.println("mark: " + buffer);

        buffer.get();

        System.out.println("-------------get......");
        System.out.println("mark: " + buffer);

        buffer.compact();

        System.out.println("-------------compact......");
        System.out.println("mark: " + buffer);

        buffer.clear();

        System.out.println("-------------clear......");
        System.out.println("mark: " + buffer);
    }
}

输出结果是:

mark: java.nio.DirectByteBuffer[pos=0 lim=1024 cap=1024]
-------------put:123......
mark: java.nio.DirectByteBuffer[pos=3 lim=1024 cap=1024]
-------------flip......
mark: java.nio.DirectByteBuffer[pos=0 lim=3 cap=1024]
-------------get......
mark: java.nio.DirectByteBuffer[pos=1 lim=3 cap=1024]
-------------compact......
mark: java.nio.DirectByteBuffer[pos=2 lim=1024 cap=1024]
-------------clear......
mark: java.nio.DirectByteBuffer[pos=0 lim=1024 cap=1024]

当分配好1024空间后,未对ByteBuffer做任何操作的时候,position最初就是0位置,limit和capcity都是1024位置,如图:

Java IO学习笔记二:DirectByteBuffer与HeapByteBuffer-LMLPHP

当put进去123三个字符以后:

Java IO学习笔记二:DirectByteBuffer与HeapByteBuffer-LMLPHP

执行flip后,pos会回到原点,lim会到目前写入的位置,这个方法主要用于读取数据:

Java IO学习笔记二:DirectByteBuffer与HeapByteBuffer-LMLPHP

调用get方法,拿出一个byte,如下图:

Java IO学习笔记二:DirectByteBuffer与HeapByteBuffer-LMLPHP

调用compact,会把前面拿掉的1个Byte位置填充:

Java IO学习笔记二:DirectByteBuffer与HeapByteBuffer-LMLPHP

调用clear会让整个内存回到初始分配状态:

Java IO学习笔记二:DirectByteBuffer与HeapByteBuffer-LMLPHP

ByteBuffer.allocate()与ByteBuffer.allocateDirect()方法的区别

可以参考:

https://stackoverflow.com/questions/5670862/bytebuffer-allocate-vs-bytebuffer-allocatedirect/5671880#5671880

allocate分配方式产生的内存开销是在JVM中的,allocateDirect分配方式产生的开销在JVM之外,以就是系统级的内存分配。系统级别内存的分配比JVM内存的分配要耗时多。所以并非不论什么时候 allocateDirect的操作效率都是很高的。

那什么时候使用堆内存,什么时候使用直接内存?

参考:NIO ByteBuffer 的 allocate 和 allocateDirect 的区别

什么情况下使用DirectByteBuffer(ByteBuffer.allocateDirect(int))?

1、频繁的native IO,即缓冲区 中转 从操作系统获取的文件数据、或者使用缓冲区中转网络数据等

2、不需要经常创建和销毁DirectByteBuffer对象

3、经常复用DirectByteBuffer对象,即经常写入数据到DirectByteBuffer中,然后flip,再读取出来,最后clear。。反复使用该DirectByteBuffer对象。

而且,DirectByteBuffer不会占用堆内存。。也就是不会受到堆大小限制,只在DirectByteBuffer对象被回收后才会释放该缓冲区。

什么情况下使用HeapByteBuffer(ByteBuffer.allocate(int))?

1、同一个HeapByteBuffer对象很少被复用,并且该对象经常是用一次就不用了,此时可以使用HeapByteBuffer,因为创建HeapByteBuffer开销比DirectByteBuffer低。

(但是!!创建所消耗时间差距只是一倍以下的差距,一般一次只会创建一个DirectByteBuffer对象反复使用,而不会创建几百个DirectByteBuffer,

所以在创建一个对象的情况下,HeapByteBuffer并没有什么优势,所以,开发中要使用ByteBuffer时,直接用DirectByteBuffer就行了)

源码

Github

06-12 15:06