继承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.") }
关键说明
- 匿名子类失效原因:
object: PhantomReference<Any>(obj!!, queue) {}这种写法创建的实例如果没有被强引用指向,会和普通对象一样被GC回收,无法等到目标对象被清理后入队。 - 无变量持有失效原因:直接执行
PhantomReference(obj!!, queue)时,实例没有任何强引用关联,会被JVM快速回收,根本无法完成入队逻辑。 - 生产环境注意:不要依赖
System.gc()保证GC立即执行,它只是触发GC的建议;持有PhantomReference的强引用要避免意外阻止目标对象被GC,只需保证引用自身存活到目标对象回收后即可。
内容的提问来源于stack exchange,提问作者Dayo
相关产品推荐
相关产品推荐

