码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 美团一面:说一说Java中的四种引用类型?


    合集 - Java(12)
    1.代码整洁之道(一)之优化if-else的8种方案01-302.提高Java开发生产力,我选Stream API,真香啊02-193.求求你别再用OkHttp调用API接口了,快来试试这款HTTP客户端库吧02-294.聊一聊日常开发中如何优雅的避免那无处不在的空指针异常03-015.乖乖,咱不用BeanUtil.copy了,咱试试这款神级工具(超详细)03-056.Java编程的利器:Pair和Triple无缝解决多值返回问题,助力编写高效代码03-047.聊一聊Integer的缓存机制问题03-068.阿里一面:Java中如何停止线程?03-149.阿里二面:如何定位&避免死锁?连着两个面试问到了!03-1310.还在用Calendar操作Date?Java8都弃用了,还不知道它的这款强大的工具吗?03-1811.Java22重磅发布!!!!卷不动了,真的卷不动了。。。。03-21
    12.美团一面:说一说Java中的四种引用类型?03-22
    收起

    引言

    在JDK1.2之前Java并没有提供软引用、弱引用和虚引用这些高级的引用类型。而是提供了一种基本的引用类型,称为Reference。并且当时Java中的对象只有两种状态:被引用和未被引用。当一个对象被引用时,它将一直存在于内存中,直到它不再被任何引用指向时,才会被垃圾回收器回收。而被引用也就是强引用。

    而在JDK1.2之后对引用的概念进行了扩充,分为了强引用(StrongReference)、软引用(SoftReference)、弱引用(WeakReference)和虚引用(PhantomReference),这4种引用的强度依次减弱。他们的关系如下如:
    image.png

    强引用

    强引用是Java中最常见的引用类型。当你创建一个对象并将其赋值给一个变量时,这个变量会持有该对象的强引用。

    Order order = new Order(); // 只要order还指向Order对象,那么Order对象就不会被回收
    order = null; // 强引用都被设置为 null 时,不可达,则Order对象被回收
    

    只要存在强引用指向对象,垃圾回收器将永远不会回收该对象,即使内存不足也不会回收。这可能导致内存溢出,因为即使内存不足,JVM也不会回收强引用对象。当强引用都被设置为null时,对象变成不可达状态,垃圾回收器会在适当的时候将其回收。

    比如以下示例,我们创建一个2M的数组,但是我们设置JVM参数:-Xms2M -Xmx3M,将JVM的初始内存设为2M,最大可用内存为3M。

    public static void main(String[] args) {  
        //定义一个2M的数组  
        byte[] objects = new byte[1024 * 1024 * 2];  
    }
    

    此时我们执行方法后,发现报错:

    image.png
    对于强引用,即使内存不够使用,直接报错OOM,强引用也不会被回收。

    对于强引用,就好比生活中,当我们拥有家里的钥匙时,我们可以随时进入你的家,即使我们不需要进入,也能确保我们可以进入。钥匙是我们进入家的强引用。只有当我们不再拥有钥匙时,我们才无法进入家,类似于当没有强引用指向一个对象时,该对象才能被垃圾回收。

    软引用

    在JDK1.2之后,用java.lang.ref.SoftReference类来表示软引用。软引用允许对象在内存不足时被垃圾回收器回收。如果一个对象只有软引用指向它,当系统内存不足时,垃圾回收器会尝试回收这些对象来释放内存,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。软引用适用于需要缓存大量对象,但又希望在内存不足时释放部分对象以避免内存溢出的情况,用于实现缓存时,当内存紧张时,可以释放部分缓存对象以保证系统的稳定性。

    以下示例我们设置JVM参数为:-Xms3M -Xmx5M,然后连续创建了10个大小为1M的字节数组,并赋值给了软引用,然后循环遍历将这些对象打印出来。

    private static final List list = Lists.newArrayList();  
      
    public static void main(String[] args) {  
        IntStream.range(0, 10).forEach(i -> {  
            byte[] buff = new byte[1024 * 1024];  
            SoftReference<byte[]> sr = new SoftReference<>(buff);  
            list.add(sr);  
        });  
      
        System.gc(); // 主动通知垃圾回收  
      
        list.forEach(l -> {  
            Object obj = ((SoftReference) l).get();  
            System.out.println("Object: " + obj);  
        });  
    }
    
    

    然后我们执行代码之后:

    image.png
    对于打印结果中,只有最后一个对象保留了下来,其他的obj全都被置空回收了。即说明了在内存不足的情况下,软引用将会被自动回收。

    对于弱引用,就像我们医药箱里的备用药,当我们需要药品时,我们会先看看医药箱里是否有备用药。如果医药箱里有足够的药品(内存足够),我们就可以使用备用药;但如果医药箱里的备用药不够了(内存不足),我们可能会去药店购买。在内存不足时,垃圾回收器可能会回收软引用对象,类似于我们在医药箱里的备用药被用完时去药店购买。

    弱引用

    JDK1.2之后,用java.lang.ref.WeakReference来表示弱引用。弱引用与软引用类似,但强度更弱。即使内存足够,只要没有强引用指向一个对象,垃圾回收器就可以随时回收该对象。弱引用适用于需要临时引用对象的场景,如临时缓存或临时存储对象。也可以用于解决对象之间的循环引用问题,避免内存泄漏。

    对于上述示例中,我们将数组赋值给弱引用

    private static final List list = Lists.newArrayList();  
      
    public static void main(String[] args) {  
        IntStream.range(0, 10).forEach(i -> {  
            byte[] buff = new byte[1024 * 1024];  
            WeakReference<byte[]> sr = new WeakReference<>(buff);  
            list.add(sr);  
        });  
      
        System.gc(); // 主动通知垃圾回收  
      
        list.forEach(l -> {  
            Object obj = ((WeakReference) l).get();  
            System.out.println("Object: " + obj);  
        });  
    }
    
    

    执行结果发现所有的对象都是null,即都被回收了。

    image.png

    对于弱引用,就像我们正在旅行,使用一张一次性地图。我们只在需要导航时使用地图,一旦旅行结束,我们就不再需要地图了。这时我们可以选择扔掉地图,类似于弱引用,在垃圾回收器运行时,无论内存是否充足,对象都可能被回收。

    虚引用

    在 JDK1.2之后,用java.lang.ref.PhantomReference类来表示虚引用。虚引用是最弱的引用类型,它几乎对对象没有任何影响,不能通过虚引用获取对象,也不能通过它来阻止对象被垃圾回收。从源码中可以看出它只有一个构造函数和一个 get() 方法,而且它的 get() 方法仅仅是返回一个null,也就是说将永远无法通过虚引用来获取对象,虚引用必须要和 ReferenceQueue 引用队列一起使用。

    image.png

    虚引用可以用于在对象被回收时进行后续操作,如对象资源释放或日志记录,常用于跟踪对象被垃圾回收的状态,执行一些清理工作。

    而对于弱引用,就像我们去商店,商店入口处的门闩并不直接影响你进入房屋,但它会在有人进入或离开时发出声音,提醒你有人进店(欢迎光临)或者离开(欢迎再来)。类似地,虚引用并不直接影响对象的生命周期,但它可以在对象被回收时发出通知,让你有机会进行一些后续操作,比如资源释放或者记录日志。

    引用队列

    引用队列(ReferenceQueue)是Java中的一个特殊队列,用于配合软引用、弱引用和虚引用,实现更灵活的对象引用和回收管理。

    引用队列的主要作用是跟踪对象的垃圾回收过程。当一个软引用、弱引用或虚引用指向的对象被垃圾回收器回收时,如果它们与一个引用队列关联,那么这些引用就会被自动加入到引用队列中。通过监视引用队列中的对象,我们可以了解到对象的回收状态,从而执行一些额外的操作,比如资源释放或日志记录等。

    总结

    Java中的四种引用类型各具特点,可根据程序需求选择合适的引用类型。强引用保证对象不被意外回收,软引用和弱引用用于实现缓存或解决内存敏感问题,而虚引用则用于对象回收后的通知和清理操作。合理使用引用类型可以更好地管理内存和避免内存泄漏问题。

    本文已收录于我的个人博客:码农Academy的博客,专注分享Java技术干货,包括Java基础、Spring Boot、Spring Cloud、Mysql、Redis、Elasticsearch、中间件、架构设计、面试题、程序员攻略等

  • 相关阅读:
    SpringMVC系列(六)之JSON数据返回以及异常处理机制
    【快应用】网页跳转快应用测试指导
    Spring
    C / C++ 内存管理
    情怀当道!小红书品牌如何靠怀旧写好营销新故事?
    Educational Codeforces Round 10
    Git - 将远程git仓库里的指定分支拉取到本地(本地不存在的分支)
    SpringBoot二手车管理系统
    【常用的 Git 命令及简要示例说明】
    进程与线程
  • 原文地址:https://www.cnblogs.com/coderacademy/p/18089036
    • 最新文章
    • 攻防演习之三天拿下官网站群
      数据安全治理学习——前期安全规划和安全管理体系建设
      企业安全 | 企业内一次钓鱼演练准备过程
      内网渗透测试 | Kerberos协议及其部分攻击手法
      0day的产生 | 不懂代码的"代码审计"
      安装scrcpy-client模块av模块异常,环境问题解决方案
      leetcode hot100【LeetCode 279. 完全平方数】java实现
      OpenWrt下安装Mosquitto
      AnatoMask论文汇总
      【AI日记】24.11.01 LangChain、openai api和github copilot
    • 热门文章
    • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
      奉劝各位学弟学妹们,该打造你的技术影响力了!
      五年了,我在 CSDN 的两个一百万。
      Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
      面试官都震惊,你这网络基础可以啊!
      你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
      心情不好的时候,用 Python 画棵樱花树送给自己吧
      通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
      13 万字 C 语言从入门到精通保姆级教程2021 年版
      10行代码集2000张美女图,Python爬虫120例,再上征途
    Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
    正则表达式工具 cron表达式工具 密码生成工具

    京公网安备 11010502049817号