直接缓冲区与非直接缓冲区的运行效率比较

590 阅读3分钟

直接缓冲区与非直接缓冲区的创建

  • 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类进行实现的。直接缓冲区的实现类DirectByteBufferput(byte) 方法的源代码(使用jdk1.8)如下:

    public ByteBuffer put(byte x) {
        unsafe.putByte(ix(nextPutIndex()), ((x)));
        return this;
    }

直接缓冲区(DirectByteBuffer)在内部使用sun.misc.Unsafe类进行值的处理。Unsafe 类的作用是 JVM 与操作系统进行直接通信,提高程序运行的效率,正如其类的名称 Unsafe 一样,该类在使用上并不是安全的,如果使用不当,那么极有可能出现处理数据上的错误,因此,该类并没有公开化(public),仅由 JDK 内部使用。 而非直接缓冲区的实现类HeapByteBufferput(byte)方法的源代码如下:

    public ByteBuffer put(byte x) {
        hb[ix(nextPutIndex())] = x;
        return this;
    }

非直接缓冲区(HeapByteBuffer)在内部直接对 byte[] hb 字节数组进行操作,而且还是在 JVM 的堆中进行数据处理,因此运行效率相对慢一些。

引用

  1. 高洪岩 著 《NIO与Socket编程技术指南》