虚引用的唯一合法用途是在对象被彻底回收后通过ReferenceQueue发出通知;它不参与存活判定、不能延缓回收、get()始终返回null,必须绑定ReferenceQueue才有效,用于确定性资源清理。

虚引用(PhantomReference)不是用来“保对象”或“取对象”的,它的唯一合法用途是:在对象被垃圾回收器**彻底回收之后**,收到一个明确的、可编程的信号——这个信号就是它自己被放入关联的 ReferenceQueue 中。
它不参与对象存活判定,只负责事后通知
只要一个对象只剩下虚引用指向它,JVM 就视同它“已无任何有效引用”,GC 可以在任意一次回收中将其清除,哪怕内存充足。它既不能延缓回收,也不能通过 get() 拿到原对象(始终返回 null)。这种“不可用性”恰恰是设计重点:避免误用,强制你把清理逻辑和对象生命周期解耦。
必须绑定 ReferenceQueue 才有意义
单独创建 PhantomReference 没有任何效果。只有把它和 ReferenceQueue 一起传入构造函数,当 GC 完成对该对象的回收(包括 finalize 阶段,如果存在且未被禁用),JVM 才会把该虚引用实例加入队列。你的程序需另起线程或轮询队列,才能感知这一事件:
- 队列中出现该虚引用 → 表明其 referent 已被完全回收,内存已释放
- 此时可安全执行资源清理,如关闭文件句柄、释放堆外内存、注销监听器等
- 注意:不能再尝试访问原对象,它已不存在;也不应再依赖其状态做判断
典型场景是替代 finalize() 做确定性资源清理
finalize() 方法已被标记为废弃,原因包括不可靠、性能差、调用时机不确定。虚引用配合队列提供了一种更可控的方式:
- NIO 的
DirectByteBuffer底层使用Cleaner(继承自PhantomReference)自动释放堆外内存 - 自定义缓存或连接池中,可在对象被回收后触发连接归还、统计上报等动作
- 监控类工具中用于追踪对象实际存活时长,辅助分析内存泄漏
和弱引用、软引用有本质区别
弱引用(WeakReference)能在 GC 后让你“尝试取回对象”,适合临时缓存;软引用(SoftReference)倾向保留到内存紧张前,适合内存敏感缓存;而虚引用连“尝试”都不允许——它只是一张“回收完成凭证”。它的价值不在持有,而在确认结束。

















