DirectByteBuffer 创建的时候,会调用cleaner = Cleaner.create(this, new Deallocator(base, size, cap)); 见下图倒数第二行
DirectByteBuffer(int cap) { // package-private
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;
}
Cleaner
private Cleaner(Object var1, Runnable var2) {
super(var1, dummyQueue);
this.thunk = var2;
}
public static Cleaner create(Object var0, Runnable var1) {
return var1 == null?null:add(new Cleaner(var0, var1));
}
public void clean() {
if(remove(this)) {
try {
this.thunk.run();
} catch (final Throwable var2) {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
if(System.err != null) {
(new Error("Cleaner terminated abnormally", var2)).printStackTrace();
}
System.exit(1);
return null;
}
});
}
}
}
new Deallocator(base, size, cap) 是一个
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);
}
}
Deallocator 这个任务什么时候会被调用呢,这样我们就要查看代码
Reference的内部类 ,见下图。这个任务在Reference加载的时候就会在static方法块里面启动
private static class ReferenceHandler extends Thread {
ReferenceHandler(ThreadGroup g, String name) {
super(g, name);
}
public void run() {
for (;;) {
Reference<Object> r;
synchronized (lock) {
if (pending != null) {
r = pending;
pending = r.discovered; // discovered指向下一个元素,像一个链表式的
r.discovered = null;
} else {
// The waiting on the lock may cause an OOME because it may try to allocate
// exception objects, so also catch OOME here to avoid silent exit of the
// reference handler thread.
//
// Explicitly define the order of the two exceptions we catch here
// when waiting for the lock.
//
// We do not want to try to potentially load the InterruptedException class
// (which would be done if this was its first use, and InterruptedException
// were checked first) in this situation.
//
// This may lead to the VM not ever trying to load the InterruptedException
// class again.
try {
try {
lock.wait();
} catch (OutOfMemoryError x) { }
} catch (InterruptedException x) { }
continue;
}
}
// Fast path for cleaners
if (r instanceof Cleaner) {
((Cleaner)r).clean();
continue;
}
ReferenceQueue<Object> q = r.queue;
if (q != ReferenceQueue.NULL) q.enqueue(r);
}
}
}
上图中的pending 内部属性是由JVM入值的,无法跟踪
本文深入探讨了Java中DirectByteBuffer的创建过程及其与Cleaner的关联,解析了内存分配与回收机制,以及Cleaner如何在Reference加载时启动,确保资源的适时释放。
775

被折叠的 条评论
为什么被折叠?



