Java中PhantomReference和ReferenceQueue的使用方法和工作机制

PhantomReference简介
PhantomReference是JDK提供的一种引用,可直译为虚引用

首先,PhantomReference引用的get方法永远返回null

其次,只被这种虚引用所引用的对象,如果没有其他额外的有效引用的话,在执行GC垃圾回收时就会被认定为是垃圾了(但不会立刻被回收)

PhantomReference的作用是帮我们跟踪下相关对象的回收情况(比如Netty就有利用PhantomReference帮开发者诊断内存泄露问题),或者做一些清理工作(类似finalize)

ReferenceQueue简介
PhantomReference的构造函数要求我们除了传入对象引用外,还要传一个ReferenceQueue进去,即实例化一个PhantomReference的时候,需要额外关联一个ReferenceQueue

这个ReferenceQueue就是用来协助我们跟踪被PhantomReference关联到的对象的

不可达与虚可达
需要注意的是,并不是创建一个PhantomReference和ReferenceQueue就一定能跟踪被GC的对象了,这里要区分两个状态,它们是不可达和虚可达

不可达:一个对象没有被有效的引用所指向,且指向该对象的PhantomReference(如果有的话)也成了垃圾
虚可达:一个对象虽然没有被有效的引用所指向,但被PhantomReference引用所关联,且关联它的PhantomReference对象被其他有效引用指到了(不算垃圾了)
对于不可达的对象,JVM会直接回收掉它,不会触发跟踪相关的事了,而如果是虚可达的话,JVM就会把它判定成垃圾,但却不去回收,而是交到关联的ReferenceQueue里面去,让我们开发人员自行处理,我们必须在处理它之后,把这个虚引用干掉,让这个被处理的对象从虚可达转到不可达,最终让它被回收掉

工作机制
当一个被PhantomReference关联过的对象是虚可达时,垃圾收集器会把这些对象放到我们构造PhantomReference时关联的ReferenceQueue里面,然后我们可以去ReferenceQueue里取出这些对象,从而知道哪些对象在GC时被回收了或做一些额外的清理工作

示例代码
public class App {

private static ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
private static List<PhantomReference> references = new ArrayList<>();
private static List<DataObj> dataObjs = new ArrayList<>();

public static void main(String[] args) throws Exception {
    for (int i = 0; i < 32; ++i) {
        DataObj obj = new DataObj();
        PhantomReference<Object> phantomReference = new PhantomReference<>(obj, referenceQueue);
        references.add(phantomReference);
        dataObjs.add(obj);
    }

    // 设置为null 让相关对象编程虚可达 被GC特殊对待一下
    dataObjs = null;

    System.gc();

    // 直接在主线程看
    Reference<?> reference = null;
    while ((reference = referenceQueue.poll()) != null) {
        System.out.println(reference);
        reference.clear();
    }
}

}

class DataObj {
}
需要说明的是,由于System.gc()不保证一定触发gc,所以要看到效果需要多执行几次

总结
PhantomReference和ReferenceQueue可以帮我们跟踪那些被GC的对象,我们用PhantomReference来关联对象,并绑定一个ReferenceQueue,当对象是虚可达的时候,就会被放到ReferenceQueue里,然后我们可以发现它并进行处理,最后要注意的是,处理完之后,要把对应的PhantomReference干掉,让对象成为不可达,最终再被GC回收,不然可能造成内存泄露哦!

Java中PhantomReference和ReferenceQueue的使用方法和工作机制

posted @   sahara-随笔  阅读(263)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
点击右上角即可分享
微信分享提示