当前位置: 首页 > article >正文

WeakReference与SoftReference以及结合ReferenceQueue实践整理

文章目录

  • 四种引用类型概述
  • WeakReference与SoftReference区别
  • ReferenceQueue详解
    • 问题
    • 生活场景类比
      • 代码实例
      • 使用场景

四种引用类型概述

强引用 (Strong Reference):是最常见的引用形式,通常我们通过 new 关键字创建的对象引用都是强引用。只要一个对象有强引用指向它,垃圾回收器就不会回收这个对象

Object obj = new Object();  // obj 是一个强引用

软引用 (Soft Reference):软引用是比强引用弱一些的引用类型,适合用来实现缓存。只有在内存不足时,垃圾回收器才会回收软引用指向的对象。使用 SoftReference 类来实现。例如:

SoftReference<Object> softRef = new SoftReference<>(new Object());

弱引用 (Weak Reference):比软引用更弱的引用类型。当垃圾回收器运行时,不论内存是否充足,只要发现某个对象只有弱引用指向它,就会回收该对象。可以使用 WeakReference 类来创建弱引用。例如:

WeakReference<Object> weakRef = new WeakReference<>(new Object());

虚引用 (Phantom Reference):最弱的引用类型,虚引用(PhantomReference)​:如果一个对象只能被 GC Root虚引用到,则和无法被GC Root引用到时一样。因此,就垃圾回收过程而言,虚引用就像不存在一样,并不会决定对象的生命周期。虚引用主要用来跟踪对象被垃圾回收器回收的活动。

WeakReference与SoftReference区别

WeakReference用于引用那些只有在没有强引用时才能被回收的对象。当一个对象只有WeakReference指向它而没有其他强引用时,垃圾收集器会在下一次进行垃圾回收时将其回收。这意味着,如果只有弱引用指向对象,那么该对象会被认为是不可达的,并在垃圾收集时被回收。
  WeakReference通常用于构建高效的缓存、观察者模式等场景,其中需要及时回收对象而不会造成内存泄漏。当没有其他强引用指向对象时,这些弱引用指向的对象会被自动清理。

String myObject = new String("Hello");
WeakReference<String> weakReference = new WeakReference<>(myObject);

// 切断强引用
myObject = null;

// 在适当的时机,垃圾收集器会回收对象
// 以下代码中,weakReference.get() 有可能返回 null

SoftReference用于引用可能还有用但并非必需的对象。与弱引用不同的是,当垃圾收集器执行垃圾回收时,只有在内存不足的情况下,才会回收被软引用指向的对象。这使得软引用非常适合实现缓存
  在内存充足的情况下,即使只有软引用指向对象,对象仍然保持在内存中。但当内存不足时,垃圾收集器会尝试回收这些被软引用指向的对象,以便释放更多内存。

String myObject = new String("Hello");
SoftReference<String> softReference = new SoftReference<>(myObject);

// 切断强引用
myObject = null;

// 在内存充足的情况下,对象可能仍然存在于软引用中
// 但当内存不足时,垃圾收集器会回收对象
// 以下代码中,softReference.get() 在内存不足时可能返回 null

WeakReference适合用于只有在没有强引用时才能被回收的对象。
SoftReference适合用于在内存不足时才被回收的对象,通常用于实现缓存等功能。
  请注意,在使用WeakReference和SoftReference时,需要根据具体情况小心地处理引用对象为空的情况,因为它们在垃圾回收时有可能返回null

ReferenceQueue详解

问题

如果一个对象只有软引用或者弱引用,则它随时可能会被 JVM垃圾回收掉。这会给我们带来的问题是我们在使用时根本无法知道它是否还存在。
可是,有时我们需要知道被软引用或者弱引用的对象在何时被回收,以便进行一些后续的处理工作。ReferenceQueue类便提供了这样的功能。ReferenceQueue本身是一个列表,我们可以在创建软引用或者弱引用的包装对象时传入该列表。这样,当 JVM 回收被包装的对象时,会将其包装类加入 ReferenceQueue类中。

生活场景类比

想象你是一家大型图书馆的管理员,图书馆里有许多书籍供读者借阅和使用。你知道这些书籍并不永远留在书架上,有时候读者借阅了书籍后就会离开,把书带走。为了保持图书馆的秩序,你需要知道哪些书已经离开图书馆,并安排人手把书的位置腾空,以供新的书籍存放。
图书馆的书籍:代表内存中的对象。它们可以被“读者”(即程序中的引用)持有或者放回。
读者离开图书馆时归还书籍:就像对象被垃圾回收一样,书籍不再被使用或占有。
ReferenceQueue(通知队列):你设立了一个专门的通知队列,当一本书离开图书馆时,图书馆的系统会通知这个队列,告诉管理员这本书的位置已经空出来了,需要清理或重新分配空间。
• 每当有读者借走书籍(对象被引用),这本书就暂时不属于书架(内存中)。
• 当这本书被归还(对象变得不可达,被垃圾回收)时,系统会通知 ReferenceQueue,让管理员知道某个位置已经空出来了。
• 管理员检查 ReferenceQueue,发现有书的位置空出来了,就会把这个位置清理,腾出空间供其他书籍使用。
ReferenceQueue 的用途和作用:在垃圾回收发生时用来通知程序哪些对象已经被回收,并在需要时执行后续操作,比如清理或释放资源。

代码实例

   public static void main(String[] args) {
        simpleRef();
        refWithReferenceQueue();
    }

    private static void simpleRef() {
        // 通过等号直接建立的引用都是强引用
        User user = new User();

        // 通过SoftReference建立的引用是软引用
        SoftReference<User> softRefUser =new SoftReference<>(new User());

        // 通过WeakReference建立的引用是弱引用
        WeakReference<User> weakRefUser = new WeakReference<>(new User());
    }

    private static void refWithReferenceQueue() {
        // 创建ReferenceQueue
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        // 用来存储弱引用的目标对象
        List<WeakReference> weakRefUserList = new ArrayList<>();
        // 创建大量的弱引用对象,交给weakRefUserList引用
        for (int i =0 ; i< 1000000; i++) { // 模拟内存不足
            // 创建弱引用对象,并在此过程中传入ReferenceQueue
            WeakReference<User> weakReference = new WeakReference(new User(Math.round(Math.random() * 1000)),referenceQueue);
            // 引用弱引用对象
            weakRefUserList.add(weakReference);
        }
        WeakReference weakReference;
        Integer count = 0;
        // 处理被回收的弱引用
        while ((weakReference = (WeakReference) referenceQueue.poll()) != null) {
            // 虽然弱引用存在,但是引用的目标对象已经为空
            System.out.println("JVM 清理了:" + weakReference + ", 从WeakReference中取出对象值为:" + weakReference.get());
            count ++;
        }
        // 被回收的弱引用总数
        System.out.println("weakReference中的元素数目为:" + count);
        // 在弱引用的目标对象不被清理时,可以引用到目标对象
        System.out.println("在不被清理的情况下,可以从WeakReference中取出对象值为:" +
                new WeakReference(new User(Math.round(Math.random() * 1000)),referenceQueue).get());
    }

   static   class User {
        private long id;

        public User() {
        }

        public User(long id) {
            this.id = id;
        }

        @Override
        public String toString() {
            return "User:" + id;
        }
    }

在这里插入图片描述

使用场景

【1】内存敏感的缓存:使用 SoftReference 来实现缓存机制,可以让应用在内存不足时自动回收缓存对象。例如,图像缓存、数据缓存等,当内存紧张时,JVM 会自动回收不再被强引用的缓存对象,从而减少内存占用。
【2】对象池管理:在对象池的实现中,使用 SoftReference 来保持对象的引用,以便在需要时快速获取对象。在内存紧张时,这些对象可以被回收,从而优化内存使用和性能。
【3】大型数据集处理:在处理大型数据集时,可以使用 SoftReference 存储中间结果。这样在内存不足时,可以让这些中间结果被回收,而不是占用大量内存,避免因内存溢出导致的崩溃。
【4】图形应用程序中的图像缓冲:在图形界面应用程序中,可以使用 SoftReference 来缓存图像。当内存不足时,图像可以被回收以释放内存,从而使应用能够继续运行而不至于崩溃。
【5】自定义数据结构:在自定义数据结构(如 LRU 缓存)中,可以使用 SoftReference 作为值来保存不常用的数据项。当内存紧张时,自动释放不再需要的数据,确保结构的内存占用保持在合理范围内。


http://www.kler.cn/a/378087.html

相关文章:

  • Visual Studio | 配置管理
  • 数据结构之线段树
  • 私有化视频平台EasyCVR视频汇聚平台接入RTMP协议推流为何无法播放?
  • 设计模式之结构型模式---装饰器模式
  • VR 创业之路:从《I Expect You To Die》到未来展望
  • 【4】函数与结构体
  • AppInventor2能否用网络摄像头画面作为屏幕的背景?
  • Golang--函数、包、defer、系统函数、内置函数
  • thinkphp8模型中 where数组条件大于,小于,like等条件时与tp5/6 的区别和使用示例
  • 3.3_JavaScript 对象与事件
  • 湖南(市场研究)源点咨询 市场调研公司与咨询公司有何不同?
  • Leetcode 腐烂的橘子
  • docker理论+部署(一)
  • masm汇编debug调试字符串大小写转换演示
  • 职场中这样汇报工作领导才满意
  • Milvus - 相似度量详解
  • HarmonyOS 5.0应用开发——用户文件操作
  • git入门教程9:配置Git钩子
  • 线程数组一例
  • 信息学科平台系统构建:Spring Boot框架深度解析
  • Kubernetes中常见的volumes数据卷
  • BES2600WM---HiLink RM56 EVK
  • 基于yolov5的输电线,电缆检测系统,支持图像检测,视频检测和实时摄像检测功能(pytorch框架,python源码)
  • 视频QoE测量学习笔记(二)
  • Python+pandas读取Excel将表头为键:对应行为值存为字典—再转json
  • el-datepicker此刻按钮点击失效