long base = 0;
try {
base = unsafe.allocateMemory(size); //分配直接内存,base表示的是直接内存的开始地址
} 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;
}
…
}
可以看到构造方法中的确是用了unsafe.allocateMemory方法帮我们分配了直接内存,另外,在构造方法的最后,通过 Cleaner.create方法注册了一个钩子函数,用于清除直接内存的引用。
Cleaner.create方法声明如下所示:
public static Cleaner create(Object heapObj, Runnable task)
其中第一个参数是一个堆内存对象,第二个参数是一个Runnable任务,表示这个堆内存对象被回收的时候,需要执行的回调方法。我们可以看到在DirectByteBuffer的最后一行中,传入的这两个参数分别是this,和一个Deallocator(实现了Runnable接口),其中this表示就是当前DirectByteBuffer实例,也就是当前DirectByteBuffer被回收的时候,回调Deallocator的run方法
Deallocator就是用于清除DirectByteBuffer引用的直接内存,代码如下所示:
private static class Deallocator
implements Runnable
{
private static Unsafe unsafe = Unsafe.getUnsafe();
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) {
// Paranoia
return;
}
unsafe.freeMemory(address);//清除直接内存
address = 0;
Bits.unreserveMemory(size, capacity);
}
}
可以看到run方法中调用了unsafe.freeMemory方法释放了直接内存的引用。
========================================================================
在DirectByteBuffer实例创建时,分配内存之前调用了Bits.reserveMemory,如果分配失败调用了Bits.unrese
【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
rveMemory,同时在Deallocator释放完直接内存的时候,也调用了Bits.unreserveMemory方法。
这两个方法,主要是记录jdk已经使用的直接内存的数量,当分配直接内存时,需要进行增加,当释放时,需要减少,源码如下:
static void reserveMemory(long size, int cap) {
//如果直接有足够多的直接内存可以用,直接增加直接内存引用的计数
synchronized (Bits.class) {
if (!memoryLimitSet && VM.isBooted()) {
maxMemory = VM.maxDirectMemory();
memoryLimitSet = true;
}
// -XX:MaxDirectMemorySize limits the total capacity rather than the
// actual memory usage, which will differ when buffers are page
// aligned.
if (cap <= maxMemory - totalCapacity) {//维护已经使用的直接内存的数量
reservedMemory += size;
totalCapacity += cap;
count++;
return;
}
}
//如果没有有足够多的直接内存可以用,先进行垃圾回收
System.gc();
try {
Thread.sleep(100);//休眠100秒,等待垃圾回收完成
} catch (InterruptedException x) {
// Restore interrupt status
Thread.currentThread().interrupt();
}
synchronized (Bits.class) {//休眠100毫秒后,增加直接内存引用的计数
if (totalCapacity + cap > maxMemory)
throw new OutOfMemoryError(“Direct buffer memory”);