前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于Java中引用的面试题

关于Java中引用的面试题

作者头像
半月无霜
发布2023-10-18 16:27:25
2400
发布2023-10-18 16:27:25
举报
文章被收录于专栏:半月无霜

关于Java中引用的面试题

一、介绍

在Java中,有以下四种类型的引用:强软弱虚

  1. 强引用(Strong Reference):最常见的引用类型,也是默认的引用类型。如果一个对象具有强引用,那么垃圾回收器就不会回收这个对象。
  2. 软引用(Soft Reference):如果一个对象具有软引用,那么当系统内存不足时,垃圾回收器会尝试回收该对象。软引用通常用于缓存中,以便在内存紧张时释放一些缓存。
  3. 弱引用(Weak Reference):如果一个对象具有弱引用,那么它的生命周期更短,它在任何时候都可能被垃圾回收器回收。弱引用通常用于外部引用内部对象时使用,以免内存泄漏。
  4. 虚引用(Phantom Reference):虚引用是所有引用类型中最弱的一种。如果一个对象具有虚引用,那么它就像没有被引用一样,随时会被垃圾回收器回收。虚引用主要用于跟踪对象被回收的状态。

上面属于Java的面试八股文,那么在面试之中,我们该如何进行理解输出呢?

二、引用

1)强引用(Strong Reference)

在日常开发中最为平常的引用,因为我们直接new出来的对象就属于强引用。

那么,如果一个对象只要有强引用,那么GC就不会回收掉它。如下这个类

代码语言:javascript
复制
package com.banmoon.reference;

public class Reference {

    @Override
    protected void finalize() throws Throwable {
        System.out.println("GC回收");
        super.finalize();
    }
}

我只有将引用设置为null后,GC才能回收掉它,强引用就是如此。

代码语言:javascript
复制
package com.banmoon.reference;

import java.io.IOException;

public class StrongReference {

    public static void main(String[] args) throws IOException {
        Reference reference = new Reference();
        System.out.println(reference);
        // 赋值为null,取消对象的强引用
        reference = null;
        // 通知进行gc
        System.gc();
        System.out.println(reference);
        // 阻塞一下
        System.in.read();
    }

}

2)软引用(Soft Reference)

软引用和强引用不同

  • 强引用只要有引用指向对象,对象就不会被回收
  • 而软引用,就算有软引用指向对象,在发生内存不足的时候,GC就会把这些软引用的对象给回收

为了测试下面的代码,我们需要添加一点JVM参数,限制一下JVM的内存,即-Xms20M -Xmx20M,我限制了20M的内存

代码语言:javascript
复制
package com.banmoon.reference;

import java.lang.ref.SoftReference;
import java.util.concurrent.TimeUnit;

public class SoftReferenceMain {

    public static void main(String[] args) throws InterruptedException {
        // 一个byte数组,内容大小是10M
        SoftReference<byte[]> sr = new SoftReference<>(new byte[1024 * 1024 * 10]);
        // 获取数组
        System.out.println(sr.get());
        // 睡眠一秒后,再次查看数组
        TimeUnit.SECONDS.sleep(1);
        System.out.println(sr.get());

        // 我再创建一个数组,12M,再次查看原来软引用的数组
        byte[] bytes = new byte[1024 * 1024 * 12];
        System.out.println(sr.get());
    }
    
}
image-20230527221108072
image-20230527221108072

3)弱引用(Weak Reference)

比起上面的两个引用,弱引用可以这样理解,它引用的对象,只要发生GC,就都会被回收。

也就是说,前两个引用都一定程度上保护了对象,但弱引用不行,弱引用保护不了任何对象。

在平常的使用中,基本没啥用,当然ThreadLocal中使用到了,搭配着强引用一起进行使用的。

简单改造一下强引用的代码,变成弱引用,GC后会发生什么

代码语言:javascript
复制
package com.banmoon.reference;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.concurrent.TimeUnit;

public class WeakReferenceMain {

    public static void main(String[] args) throws IOException, InterruptedException {
        WeakReference<Reference> wr = new WeakReference<>(new Reference());
        System.out.println(wr.get());
        // 通知进行gc,并阻塞一下
        System.gc();
        TimeUnit.SECONDS.sleep(1);
        // 查看输出
        System.out.println(wr.get());
    }

}
image-20230527221746422
image-20230527221746422

4)虚引用(Phantom Reference)

最后一个虚引用,比较特殊。主要是给GC使用的,对的没错,JVMGC的时候,也会创建对象,这些基本就是虚引用。

下面作为示例了解一下

代码语言:javascript
复制
package com.banmoon.reference;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

public class PhantomReferenceMain {

    public static void main(String[] args) throws InterruptedException {
        ReferenceQueue<Reference> queue = new ReferenceQueue<>();
        PhantomReference<Reference> phantom = new PhantomReference<>(new Reference(), queue);

        //检查垃圾回收队列中是否已经加入该对象
        System.out.println("Is queued: " + phantom.isEnqueued());

        //强制进行垃圾回收并等待GC完成
        System.gc();
        Thread.sleep(1000);

        //检查垃圾回收队列中是否已经加入该对象
        System.out.println("Is queued: " + phantom.isEnqueued());

        //从队列中读取并打印垃圾回收的信息
        System.out.println(queue.poll());
    }

}

虚引用的使用场景 虚引用通常用于实现比弱引用更加精细的对象 finalization(终结)处理逻辑。虚引用通常与引用队列结合使用,对于一个具有虚引用的对象,当垃圾回收器准备回收该对象时,如果发现它存在虚引用,就会在回收对象的内存之前,将这个虚引用加入到与之关联的引用队列中。 在实际应用中,虚引用常用于:

  1. 用于在对象被回收时进行一些定制操作,例如发送通知、记录日志、清理资源等等。
  2. 用于避免内存泄漏,通过使用虚引用表示该对象将会被垃圾回收器回收,并触发一些清理操作。

值得注意的是,虚引用并不会影响被引用对象的生命周期。当垃圾回收器准备回收对象时,虚引用会被加入到与之关联的引用队列中,但此时虚引用本身并不能保证被回收,需要不断调用getReference()方法来获取引用队列中的虚引用,直到返回null为止。

三、最后

关于GC回收强引用的对象,有时候就算被强引用,也还是会被回收的场景,比如说循环引用。所以还是得具体情况,具体分析。

我是半月,你我一同共勉!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-05-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关于Java中引用的面试题
    • 一、介绍
      • 二、引用
        • 1)强引用(Strong Reference)
        • 2)软引用(Soft Reference)
        • 3)弱引用(Weak Reference)
        • 4)虚引用(Phantom Reference)
      • 三、最后
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档