Buffer

allocate()

ByteBuffer.allocat()
public static ByteBuffer allocate(int capacity) {
    if (capacity < 0)
        throw new IllegalArgumentException();
    // 堆内缓存区
    return new HeapByteBuffer(capacity, capacity);
}
ByteBuffer.allocateDirect()
public static ByteBuffer allocateDirect(int capacity) {
    // 对外缓存区
    return new DirectByteBuffer(capacity);
}

HeapByteBuffer

内存是分配在堆上的,直接由Java虚拟机负责垃圾收集。

创建HeapByteBuffer
HeapByteBuffer(int cap, int lim) {        
    super(-1, 0, lim, cap, new byte[cap], 0);
}
ByteBuffer
ByteBuffer(int mark, int pos, int lim, int cap,   
             byte[] hb, int offset)
{
    super(mark, pos, lim, cap);
    this.hb = hb;
    this.offset = offset;
}
Buffer
Buffer(int mark, int pos, int lim, int cap) {  
    if (cap < 0)
        throw new IllegalArgumentException("Negative capacity: " + cap);
    this.capacity = cap;
    limit(lim);
    position(pos);
    if (mark >= 0) {
        if (mark > pos)
            throw new IllegalArgumentException("mark > position: ("
                                               + mark + " > " + pos + ")");
        this.mark = mark;
    }
}

DirectByteBuffer

是通过JNI在Java虚拟机外的内存中分配了一块(java堆内存由Xmx控制,而堆外内存由-XX:MaxDirectMemorySize控制),该内存块并不直接由Java虚拟机负责垃圾收集,但是在DirectByteBuffer包装类被回收时,会通过Java Reference机制来释放该内存块。

DirectByteBuffer
DirectByteBuffer(int cap) {     
              
    super(-1, 0, cap, cap);
    boolean pa = VM.isDirectMemoryPageAligned();
    int ps = Bits.pageSize();
    long size = Math.max(1L, (long)cap + (pa ? ps : 0));
    Bits.reserveMemory(size, cap);

    long base = 0;
    try {
        base = unsafe.allocateMemory(size);
    } catch (OutOfMemoryError x) {
        Bits.unreserveMemory(size, cap);
        throw x;
    }
    unsafe.setMemory(base, size, (byte) 0);
    if (pa && (base % ps != 0)) {
        // Round up to page boundary
        address = base + ps - (base & (ps - 1));
    } else {
        address = base;
    }
    cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
    att = null;
}

比较

对于HeapByteBuffer,数据的分配存储都在jvm堆上,当需要和io设备打交道的时候,会将jvm堆上所维护的byte[]拷贝至堆外内存,然后堆外内存直接和io设备交互。如果直接使用DirectByteBuffer,那么就不需要拷贝这一步,将大大提升io的效率,这种称之为零拷贝(zero-copy)。

Last updated