You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

继承PhantomReference后对象无法回收?引用未入队问题排查

自定义PhantomReference无法进入ReferenceQueue的解决方案

问题本质

不管是使用匿名子类实现PhantomReference,还是直接创建PhantomReference实例但不赋值给变量,核心原因都是:PhantomReference自身没有被强引用持有,导致它在目标对象被GC回收前就被提前清理了,自然无法进入ReferenceQueue完成后续逻辑。

解决方法

必须确保自定义的PhantomReference实例被强引用持有,比如赋值给变量、存入全局集合或类的静态字段中,避免它被提前GC。

修正后的示例代码

val queue = ReferenceQueue<Any>()
var obj: Any? = Any()

// 自定义PhantomReference子类,添加清理本地资源所需的额外字段
class CustomPhantomReference<T>(
    referent: T,
    queue: ReferenceQueue<in T>
) : PhantomReference<T>(referent, queue) {
    // 示例:存储需要清理的本地资源标识
    val nativeResourceId = "native-resource-123"
}

// 用变量强引用持有自定义PhantomReference实例,避免它被提前GC
val phantomRef = CustomPhantomReference(obj!!, queue)

println("Created Custom PhantomReference")

obj = null // 清除目标对象的强引用
System.gc() // 触发垃圾回收
Thread.sleep(1000) // 等待GC执行完成

val ref = queue.poll()
if (ref != null) {
    println("Custom PhantomReference enqueued!")
    // 转型为自定义类,获取资源信息并执行清理逻辑
    (ref as CustomPhantomReference<*>).run {
        println("开始清理本地资源: $nativeResourceId")
        // 这里添加实际的本地资源释放代码
    }
} else {
    println("Custom PhantomReference not enqueued.")
}

关键说明

  1. 匿名子类失效原因:object: PhantomReference<Any>(obj!!, queue) {}这种写法创建的实例如果没有被强引用指向,会和普通对象一样被GC回收,无法等到目标对象被清理后入队。
  2. 无变量持有失效原因:直接执行PhantomReference(obj!!, queue)时,实例没有任何强引用关联,会被JVM快速回收,根本无法完成入队逻辑。
  3. 生产环境注意:不要依赖System.gc()保证GC立即执行,它只是触发GC的建议;持有PhantomReference的强引用要避免意外阻止目标对象被GC,只需保证引用自身存活到目标对象回收后即可。

内容的提问来源于stack exchange,提问作者Dayo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 01:30:11