【Java】 DirectByteBuffer堆外内存回收( 二 )


DirectByteBuffer堆外内存回收在DirectByteBuffer的构造函数中,在申请内存之前,先调用了BitsreserveMemory方法回收内存,申请内存之后,调用Cleanercreate方法创建了一个Cleaner对象,并传入了当前对象(DirectByteBuffer)和一个Deallocator类型的对象:
class DirectByteBuffer extends MappedByteBuffer implements DirectBuffer {private final Cleaner cleaner;DirectByteBuffer(int cap) {// package-privatesuper(-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 boundaryaddress = base + ps - (base & (ps - 1));} else {address = base;}// 创建Cleader,传入了当前对象和Deallocatorcleaner = Cleaner.create(this, new Deallocator(base, size, cap));att = null;}}Cleaner从名字上可以看出与清理有关,BitsreserveMemory方法底层也是通过Cleaner来进行清理,所以Cleaner是重点关注的类 。
DeallocatorDirectByteBuffer的一个内部类,并且实现了Runnable接口,在run方法中可以看到对内存进行了释放,接下来就去看下在哪里触发Deallocator任务的执行:
class DirectByteBuffer extends MappedByteBuffer implements DirectBuffer {private static class Deallocator implements Runnable {// ...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);}}}CleanerCleaner继承了PhantomReferencePhantomReferenceReference的子类,所以Cleaner是一个虚引用对象 。

【Java】 DirectByteBuffer堆外内存回收

文章插图
创建Cleaner虚引用需要与引用队列结合使用,所以在Cleaner中可以看到有一个ReferenceQueue,它是一个静态的变量,所以创建的所有Cleaner对象都会共同使用这个引用队列 。
在创建Cleaner的create方法中,处理逻辑如下:
  1. 通过构造函数创建了一个Cleaner对象,构造函数中的referent参数为DirectByteBuffer,thunk参数为Deallocator对象,在构造函数中又调用了父类的构造函数完成实例化;
  2. 调用add方法将创建的Cleaner对象加入到链表中,添加到链表的时候使用的是头插法,新加入的节点放在链表的头部,first成员变量是一个静态变量,它指向链表的头结点,创建的Cleaner都会加入到这个链表中;
创建后的Cleaner对象处于Active状态 。
public class Cleaner extends PhantomReference<Object>{// ReferenceQueue队列private static final ReferenceQueue<Object> dummyQueue = new ReferenceQueue<>();// 静态变量,链表的头结点,创建的Cleaner都会加入到这个链表中static private Cleaner first = null;// thunkprivate final Runnable thunk;public static Cleaner create(Object ob, Runnable thunk) {if (thunk == null)return null;// 创建一个Cleaner并加入链表return add(new Cleaner(ob, thunk));}private Cleaner(Object referent, Runnable thunk) {super(referent, dummyQueue); // 调用父类构造函数,传入引用对象和引用队列this.thunk = thunk; // thunk指向传入的Deallocator}private static synchronized Cleaner add(Cleaner cl) {// 如果头结点不为空if (first != null) {// 将新加入的节点作为头结点cl.next = first;first.prev = cl;}first = cl;return cl;}}

经验总结扩展阅读