一、概述
ByteBuffer 属于 java.nio 包下的类,它是 Java 提供的堆外内存的 Buffer,主要用于 Java NIO 编程中。
二、源码
DirectByteBuffer(int cap) {super(-1, 0, cap, cap, null);boolean pa = VM.isDirectMemoryPageAligned();int ps = Bits.pageSize();long size = Math.max(1L, (long)cap + (pa ? ps : 0));// 强制执行 Full GC,但一般生产环境都是设置了 -XX:DisableExplicitGC,所以是不起作用的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 boundaryaddress = base + ps - (base & (ps - 1));} else {address = base;}// 创建 Cleaner 对象,负责堆外内存回收工作。// 虚引用(PhantomReference)和 ReferenceQueue 配合使用达到回收堆外内存的目的// Deallocator 内部持有堆外内存基地址以及大小和容量,并有一个 run方法用以释放堆外内存// Cleaner 是一个双端链表,create包含add方法,添加到首部位置// 当 堆内的 DirectByteBuffer 对象被回收,同时也表示其指向的堆外内存也需要被回收,// 这时,Cleaner对象不再有任何引用关系,在下一次 GC 时,该 Cleaner对象将被添加到 ReferenceQueue// 中并执行 clean() 方法,它主要做两件事件// 1.将 Cleaner 对象从链表中移除// 2.调用 UNSAFE.freeMemory(address); 方法清理堆外内存cleaner = Cleaner.create(this, new Deallocator(base, size, cap));att = null;}private static class Deallocator implements Runnable {private long address;private long size;private int capacity;private Deallocator(long address, long size, int capacity) {assert (address != 0);this.address = address;this.size = size;this.capacity = capacity;}public void run() {if (address == 0) {// Paranoiareturn;}// 释放堆外内存UNSAFE.freeMemory(address);address = 0;// 重置大小和容量Bits.unreserveMemory(size, capacity);}}
