【面试】JAVA四种引用 -强引用、软引用、弱引用、虚引用

本文详细介绍了Java中的四种引用类型:强引用、软引用、弱引用和虚引用,以及它们在内存管理和缓存策略中的应用。通过示例代码展示了不同引用类型的对象在GC过程中的行为,强调了在面临内存限制时如何选择合适的引用类型来优化内存使用。此外,还提到了Cleaner类在对象回收时清理关联资源的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

概述

强引用

软引用

典型使用场景

弱引用

典型使用场景

虚引用

 典型使用场景

场景验证

Cleaner

示例代码

输出结果


概述

        Java中的引用关系可以分为强引用,软引用(SoftReference)、弱引用(WeakReference)和虚引用(PhantomReference);引用与对象以及GC Root直接的关系如下图所示:

强引用

     强引用就是普通的赋值语句,只要GC Root到对象之间存在引用关系,改对象就不会被回收

软引用

        软引用要弱于强引用,在GC Root 到引用对象之间还存在可达关系,只要JVM认为存在OOM风险就可以被回收

典型使用场景

        1.缓存,被回收不影响系统可用性;比如在JDK反射中使用较多

弱引用

        弱引用关系要比软引用之间的关系更弱,只要发生GC就会被回收,不管内存空间是否充足;也可以配合引用队列使用

典型使用场景

        1.缓存,比如WeakHashMap, ThreadLocal等

虚引用

        虚引用是最特殊的一个引用,虚引用的简单来讲就是形同虚设,无法从引用中获取引用对象,既然这样,虚引用的作用是什么呢?它主要用来跟踪对象被垃圾回收的活动,当垃圾
回收器准备回收这个对象时,如果发现它有虚引用就会将这个虚引用添加到与之关联的引用队列中。

 典型使用场景

      对象回收时,清理关联资源,比如Cleaner,以及堆外缓存管理等。

场景验证

为了验证是引用关系是否如上文所述,特准备如下代码:

public class 四种引用 {



    public static void main(String[] args) throws InterruptedException {


        //强引用
        Object strongReference = new Object();

        //引用队列
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        /**
         * 软引用
         * 如果仅有软引用对象时,首次垃圾回收不会回收改对象,再次回收时才会回收改对象
         * 软引用可以配合引用队列使用
         */
        SoftReference<Object> softReference = new SoftReference<>(new Object(), referenceQueue);

        //reference handler
        new Thread(() -> {
            try {
                Reference<? extends Object> reference = null;
                while ((reference = referenceQueue.remove()) != null) {
                    if (reference instanceof SoftReference) {
                        System.out.println("软引用引用对象被回收");
                    }
                    if (reference instanceof PhantomReference) {
                        System.out.println("虚引用引用对象被回收");
                    }
                    if (reference instanceof WeakReference) {
                        System.out.println("弱引用引用对象被回收");
                    }
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();
        /**
         * 如果仅有弱引用,只要发生垃圾回收就会回收改对象
         */
        WeakReference<Object> weakReference = new WeakReference<>(new Object(), referenceQueue);

        System.out.println("弱引用:" + weakReference.get());
        //手动执行GC,
        System.gc();
        // 手动执行GC 后 弱引用被引用的对象已经被回收了,此时get到的值为null
        System.out.println("弱引用:" + weakReference.get());

        /**
         * 必须配合引用队列使用,当虚引用引用的对象回收时,会将徐引用对象入队,由Referen Handler线程释放其关联的外部资源
         */
        PhantomReference<Object> phantomReference = new PhantomReference<>(new Object(), referenceQueue);


        try {
            SoftReference<HashMap> holder = new SoftReference<>(new HashMap<>());
            for (int i = 0; i < 1000; i++) {
                HashMap hashMap = holder.get();
                Thread.sleep(20);
                if (Objects.nonNull(hashMap)) {
                    hashMap.put(i, new Object[1024]);
                }
                if (softReference.get() == null) {
                    System.out.println("强引用: " + strongReference);
                    System.out.println("软引用:" + softReference.get());
                    break;
                }
            }
        } catch (Throwable e) {
            System.out.println("OutOfMemoryError后:" + softReference.get());
        }
        System.out.println("强引用: " + strongReference);
        System.out.println("软引用:" + softReference.get());
        System.out.println("弱引用:" + weakReference.get());
        System.out.println("虚引用 " + phantomReference.get());

        TimeUnit.SECONDS.sleep(20);
        System.exit(-1);
    }
    
}

jvm 参数:-Xms3m -Xmx3m 执行结果如下:


弱引用:java.lang.Object@5ca881b5
[0.087s][info   ][gc,start    ] GC(1) Pause Full (System.gc())
弱引用引用对象被回收
弱引用:null
[1.193s][info   ][gc,ergo        ] Attempting maximum full compaction clearing soft references
软引用引用对象被回收
虚引用引用对象被回收
强引用: java.lang.Object@24d46ca6
软引用:null
强引用: java.lang.Object@24d46ca6
软引用:null
弱引用:null
虚引用 null

Cleaner

         在程序执行过程中创建的对象将由垃圾收集器 (GC)自动删除。当某个对象未被任何线程引用时,并且当JVM确定无法访问该对象时,则可以进行垃圾回收。
 Object类具有finalize() 方法,在尝试从堆中删除对象之前,GC 将自动调用该方法。在Java 9中,已经不建议使用finalize()方法,并将新类java.lang.ref.Cleaner 添加到垃圾回收管理中。当对象可以进行垃圾回收时,Cleaner 类的对象会自动得到通知。需要通过使用register()方法向清理器对象注册正在垃圾回收的对象

示例代码

public class CleanerTest {
    public static void test() {
        Object instance = new Object();
        Cleaner cleaner = Cleaner.create();
        cleaner.register(instance, () -> {
            System.out.println("do cleaner");
        });
    }

    public static void main(String[] args) {
        System.out.println("Cleaner Test");
        test();
        System.gc();
    }
}

输出结果

Cleaner Test
do cleaner

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈脩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值