查看原文
其他

四种引用方式,一览无余!掌握引用的区别,轻松提升代码效率!

编程导航-聪 面试鸭 2024-03-29

引言:在面试过程中,相信有很多小伙伴们都会被面试官问到一个问题,强引用、软引用、弱引用、幻象引用有什么区别?如果你从来都没听说过这样几个词,相信在面对面试官的时候将会胆怯,那么请跟着本文来学习这个知识点,铸造打败面试官的利剑吧!

强引用、软引用、弱引用、幻象引用有什么区别?

题目

强引用、软引用、弱引用、幻象引用有什么区别?

推荐解析

引用类型有哪些?

1)强引用:最普遍的引用类型,如果一个对象具有强引用,垃圾回收器绝不会回收它。当内存空间不足时,Java 宁愿抛出 OutOfMemoryError 也不会回收这种对象。

2)软引用:用来描述一些有用但非必需的对象。在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围进行第二次回收。如果回收后还没有足够的内存,才会抛出内存溢出异常。

3)弱引用:强度比软引用更弱,被弱引用关联的对象只能生存到下一次垃圾回收发生之前。当垃圾回收器工作时,无论当前内存空间足够与否,都会回收只被弱引用关联的对象。

4)幻象引用(虚引用):最弱的一种引用关系,一个对象是否有幻象引用的存在,完全不会对其生存时间构成影响,也无法通过幻象引用来取得一个对象实例。幻象引用主要用于跟踪对象被垃圾回收的活动。

应用场景有哪些?

1)强引用:最常见的应用场景,比如普通对象引用。它主要用于程序的正常运行过程中,保持对象活跃以满足程序需求。

// obj 就是强引用。
Object obj = new Object()

2)软引用:适用于实现内存敏感的缓存。软引用对象在内存足够时会保留在内存中,当内存不足时可被自动回收,这样可以在提高性能的同时避免 OOM 。(适合于实现缓存机制,如图片缓存或其他大型对象的缓存,特别是在内存使用需灵活管理的场景中。)

public class SoftReferenceCache {

    private final Map<String, SoftReference<Object>> cache = new HashMap<>();

    public void addToCache(String key, Object value) {
        SoftReference<Object> softRef = new SoftReference<>(value);
        cache.put(key, softRef);
    }

    public Object getFromCache(String key) {
        SoftReference<Object> softRef = cache.get(key);
         // 如果对象存在则返回,回收了则返回 null
        if (softRef != null) {
            return softRef.get();
        }
        return null;
    }

    public static void main(String[] args) {
        SoftReferenceCache cache = new SoftReferenceCache();
        // 添加对象缓存
        cache.addToCache("key1"new Object());
        cache.addToCache("key2"new Object());

        // 从缓存获取对象
        System.out.println(cache.getFromCache("key1"));
        System.out.println(cache.getFromCache("key2"));

        // 强制gc清除软引用
        System.gc();

        // 再次获取缓存
        System.out.println(cache.getFromCache("key1"));
        System.out.println(cache.getFromCache("key2"));
    }
}

3)弱引用:常用于实现对对象的非强制性引用的缓存,如 WeakHashMap,弱引用对象在下一次垃圾回收时无论内存是否足够都会被回收。

// 创建一个对象
Object referent = new Object();
// 创建一个弱引用来引用这个对象
WeakReference<Object> weakReference = new WeakReference<>(referent);
//或者使用 WeakHashMap 也可以达到上面效果
//Map<Object, String> weakHashMap = new WeakHashMap<>();

// 检查是否可以通过弱引用获取对象
System.out.println(weakReference.get());

// 提示垃圾回收器执行回收
referent = null;
System.gc();

// 再次检查弱引用,对象可能已被回收
System.out.println("After GC : " + weakReference.get());

4)幻像引用:幻象引用主要用于在对象被收集器回收时收到一个系统通知或者后续处理资源释放工作。

public class PhantomReferenceExample {
    public static void main(String[] args) {
        // 创建一个引用队列
        ReferenceQueue<MyObject> referenceQueue = new ReferenceQueue<>();

        // 创建一个对象
        MyObject myObject = new MyObject("Test Object");

        // 创建一个幻象引用,引用到我们的对象和引用队列
        PhantomReference<MyObject> phantomReference = new PhantomReference<>(myObject, referenceQueue);

        // 确保强引用被清除,以便垃圾收集器可以回收该对象
        myObject = null;

        // 强制进行垃圾回收,以便能快速看到效果
        System.gc();

        // 检查引用队列,看是否已经加入了幻象引用
        System.out.println("Checking reference queue...");
        if (referenceQueue.poll() != null) {
            System.out.println("Phantom reference object is enqueued.");
        } else {
            System.out.println("Phantom reference object is not enqueued.");
        }
    }
}

加深记忆的例子

1)强引用:就像是你家的房产证,只要你手里持有,这套房子就属于你,不会被任何人拿走。即便是在财政紧张的情况下,这份证明也确保了你对房产的所有权。

2)软引用:相似于你对某款限量版的珍藏品的拥有,当你的空间足够,你可以随意欣赏它。但如果你需要腾出空间(比如财务紧张),你可能会考虑出售这个珍藏品。这意味着,它对你而言是有价值的,但在特定情况下,你也愿意放手。

3)弱引用:就像是图书馆的借书证,允许你借阅图书,但书籍并非你的私有财产。一旦图书馆需要书回,或者借书期限到了,你就必须归还。这就像是弱引用管理的对象,只要垃圾收集器来扫描,不考虑当前内存空间是否足够,都会被回收。

4)幻象引用:可以想象成是对一个传说中的宝藏的追寻。你有它的地图,知道它的大概位置,但实际上你永远无法触摸到它。宝藏在你心中,影响你的行动,但当真正寻找时,它似乎并不真实存在。当对象被垃圾收集时,幻象引用就像是这个宝藏的最后一次回声,提醒你对象即将被彻底删除,但你却无法通过这个引用来访问对象本身。

其他补充

鱼聪明 AI 的回答:

鱼聪明 AI 地址:https://www.yucongming.com/

垃圾回收行为的影响

  • 强引用对象只有在显式置为 null 或失去引用时才可能被回收,可能导致内存泄露。
  • 软引用弱引用提供了更细致的控制,允许垃圾回收器在内存不足时回收这些对象,减轻内存压力。
  • 幻象引用主要用于跟踪对象回收过程,不直接决定对象的回收,但可以用于资源释放和清理工作。

性能考虑

  • 使用软引用和弱引用可能影响性能,因为它们增加了垃圾回收器的工作量。合理使用可以避免内存泄露,但过度依赖可能导致频繁的垃圾回收操作,影响应用性能。
  • 应用程序设计时需要权衡内存使用和性能,尤其是在设计高性能缓存和资源管理策略时。

API和工具

  • ReferenceQueue:与软引用、弱引用和幻象引用配合使用,可以跟踪 JVM 回收对象的时间。
  • WeakHashMap :使用弱键,允许在不再有其他强引用指向键时自动删除映射项,适合创建缓存。
  • SoftReferenceWeakReference类:提供了软引用和弱引用的实现,可以用于实现对内存敏感的缓存。

推荐文章和书籍

文章:https://zhuanlan.zhihu.com/p/86293659

书籍:《 Java 核心技术卷 I 》

欢迎交流

在阅读完本文后,你应该对 Java 中的强引用、软引用、弱引用、和幻象引用有了深入的理解。掌握了这些引用类型,你一定能在讨论 Java 内存管理和对象回收机制时,与面试官或同行进行深入的交流。本文最后提出三个问题,欢迎大家在评论区分享观点,以促进共同进步:

1)在哪些场景下应该优先考虑使用强引用、软引用、弱引用和幻象引用,以优化内存管理?

2)如何合理利用软引用和弱引用构建高效且自适应的缓存机制?

3)强引用、软引用、弱引用和幻象引用在垃圾收集过程中的行为有何不同,这些差异如何影响应用的性能和稳定性?

这些问题旨在深化对 Java 引用类型及其在实际应用中的作用的理解,期待你的参与和贡献。


继续滑动看下一个
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存