虚引用(phantomreference)适合需要精确控制对象回收时机并执行清理操作的场景,例如在堆内存不足前触发资源释放或记录日志。具体做法是配合 referencequeue 使用,当垃圾回收器发现对象仅存在虚引用时,会将该引用入队,开发者通过轮询队列获取通知并执行后续逻辑。

虚引用与软、弱引用的区别是什么
虚引用主要用于跟踪对象的回收状态,而软引用和弱引用则用于管理内存容量。软引用在内存充足时保留对象,弱引用在下一次 GC 时即被回收,只有虚引用必须关联队列才能生效,且不影响对象的存活状态。

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
public class ReferenceComparison {
public static void main(String[] args) throws InterruptedException {
// 创建测试对象
Object obj = new Object();
// 定义队列
ReferenceQueue<object> queue = new ReferenceQueue();
// 创建不同类型的引用
WeakReference<object> weakRef = new WeakReference(obj, queue);
PhantomReference<object> phantomRef = new PhantomReference(obj, queue);
// 断开强引用
obj = null;
// 触发 GC
System.gc();
Thread.sleep(100); // 等待 GC 完成
// 检查弱引用
System.out.println("WeakRef isNull: " + weakRef.get() == null);
// 检查虚引用是否入队
Reference> polled = queue.poll();
System.out.println("PhantomRef enqueued: " + (polled == phantomRef));
}
}</object></object></object>
运行结果:
WeakRef isNull: true
PhantomRef enqueued: true
如何正确使用虚引用进行资源清理
正确使用虚引用需要确保对象没有强引用指向它,并且必须提供一个非空的 ReferenceQueue。清理逻辑通常在单独的线程中运行,不断从队列中取出引用并处理关联的资源。

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.nio.ByteBuffer;
import java.util.concurrent.ConcurrentLinkedQueue;
public class PhantomCleanupDemo {
private static final ReferenceQueue<bytebuffer> QUEUE = new ReferenceQueue();
private static final ConcurrentLinkedQueue<phantomreference>> CLEANUP_QUEUE = new ConcurrentLinkedQueue();
public static void main(String[] args) {
// 启动清理线程
Thread cleanupThread = new Thread(() -> {
while (true) {
try {
Reference extends ByteBuffer> ref = QUEUE.remove();
if (ref instanceof PhantomReference) {
CLEANUP_QUEUE.add((PhantomReference<bytebuffer>) ref);
}
} catch (InterruptedException e) {
break;
}
}
});
cleanupThread.setDaemon(true);
cleanupThread.start();
// 模拟分配大缓冲区
ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024);
PhantomReference<bytebuffer> phantomRef = new PhantomReference(buffer, QUEUE);
CLEANUP_QUEUE.add(phantomRef);
buffer = null; // 移除强引用
// 触发 GC
System.gc();
try { Thread.sleep(500); } catch (InterruptedException e) {}
// 检查清理队列
System.out.println("Cleanup Queue Size: " + CLEANUP_QUEUE.size());
}
}</bytebuffer></bytebuffer></phantomreference></bytebuffer>
运行结果:
Cleanup Queue Size: 1
虚引用在 DirectByteBuffer 中的应用原理
Java NIO 中的 DirectByteBuffer 使用虚引用来确保堆外内存(Off-Heap Memory)能够被正确释放。因为堆外内存不受 JVM 堆内存管理的直接约束,JVM 无法自动回收这部分内存,所以通过虚引用机制,在对象被回收时触发清理操作,调用 Cleaner 来释放堆外内存。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











