直接缓冲区与非直接缓冲区的创建
-
allocateDirect(int capacity):分配新的直接缓字节缓冲区。新缓冲区的位置将为 0,其界限将为其容量,其标记是不确定的。无论它是否具有底层实现数组,其标记都是不确定的。创建出来的缓冲区类型为
DirectByteBuffer。使用allocateDirect()方法创建 ByteBuffer 缓冲区时,capacity 指的是字节的个数,而创建 IntBuffer 缓冲区时,capacity 指的是 int值的数目,如果要转换成字节,则 capacity 的值要乘以 4,来算出占用的总字节数。 -
allocate(int capacity):分配一个非直接字节缓冲区。新缓冲区的位置将为 0,其界限将为其容量,其标记是不确定的。它将具有一个底层实现数组,且数据偏移量将为 0。创建出来的缓冲区类型为
HeapByteBuffer。
直接缓冲区与非直接缓冲区的运行效率测试代码
直接缓冲区的运行效率测试代码如下:
package me.qianlv.bytebuffer;
import java.nio.ByteBuffer;
/**
* 直接缓冲区的运行效率
*
* @author xiaoshu
*/
public class Test1_1 {
public static void main(String[] args) {
long beginTime = System.currentTimeMillis();
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1900000000);
for (int i = 0; i < 1900000000; i++) {
byteBuffer.put((byte) 123);
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - beginTime);
}
}
程序运行结果如下:
1840
使用非直接缓冲区的测试代码如下:
package me.qianlv.bytebuffer;
import java.nio.ByteBuffer;
/**
* 非直接缓冲区的运行效率
*
* @author xiaoshu
*/
public class Test1_2 {
public static void main(String[] args) {
long beginTime = System.currentTimeMillis();
ByteBuffer byteBuffer = ByteBuffer.allocate(1900000000);
for (int i = 0; i < 1900000000; i++) {
byteBuffer.put((byte) 123);
}
long endTime = System.currentTimeMillis();
System.out.println(endTime - beginTime);
}
}
程序运行结果如下:
2309
从运行结果来看,直接缓冲区比非直接缓冲区在运行效率上要高一些,是什么原因造成这样的结果呢?
直接缓冲区比非直接缓冲区运行效率高的原因
直接缓冲区使用DirectByteBuffer来进行实现的,而非直接缓冲区是使用HeapByteBuffer类进行实现的。直接缓冲区的实现类DirectByteBuffer的 put(byte) 方法的源代码(使用jdk1.8)如下:
public ByteBuffer put(byte x) {
unsafe.putByte(ix(nextPutIndex()), ((x)));
return this;
}
直接缓冲区(DirectByteBuffer)在内部使用sun.misc.Unsafe类进行值的处理。Unsafe 类的作用是 JVM 与操作系统进行直接通信,提高程序运行的效率,正如其类的名称 Unsafe 一样,该类在使用上并不是安全的,如果使用不当,那么极有可能出现处理数据上的错误,因此,该类并没有公开化(public),仅由 JDK 内部使用。
而非直接缓冲区的实现类HeapByteBuffer的put(byte)方法的源代码如下:
public ByteBuffer put(byte x) {
hb[ix(nextPutIndex())] = x;
return this;
}
非直接缓冲区(HeapByteBuffer)在内部直接对 byte[] hb 字节数组进行操作,而且还是在 JVM 的堆中进行数据处理,因此运行效率相对慢一些。
引用
- 高洪岩 著 《NIO与Socket编程技术指南》