Garbage Collection -- 03 -- Java中的四种引用

无论是通过引用计数算法判断对象的引用数量,还是通过可达性分析算法判断对象的引用链是否可达,判定对象是否存活都与 “引用” 有关

在 JDK2 之前,Java中关于引用的定义很传统:如果 reference 类型的数据中存储的数值代表的是另一块内存的起始地址,就称这块内存代表着一个引用。这种定义很纯粹,但是太过狭隘,一个对象在这种定义下只有被引用或者没有被引用两种状态,对于如何描述一些 “食之无味,弃之可惜” 的对象就显得无能为力了。我们希望描述描述这样一类对象:当内存空间还足够时,则能保存在内存之中;如果内存空间在进行垃圾收集后还是非常紧张,则可以抛弃这些对象

在 JDK2 之后,Java 对引用的概念进行了扩充,将引用分为了强引用 (Strong Reference)、软引用 (Soft Reference)、弱引用 (Weak Reference)、虚引用 (Phantom Reference) 这四种,这四种引用强度依次逐渐减弱: 强引用 > 软引用 > 软引用 > 虚引用


一、强引用

  • 强引用是指程序代码中普遍存在的,类似于 “Object obj = new Object()” ,只要强引用还存在,则 GC 永远不会回收掉被引用的对象

  • 在内存空间不足的时候,Java 虚拟机宁可抛出 OutOfMemoryError 异常终止应用程序,也不会回收具有强引用的对象。通过将对象的引用设置为 null 的方式来弱化引用,使其被回收;或者等待它超出对象的生命周期范围,这时候 GC 会认为该对象不存在引用,从而回收该对象

  • 举例说明

    String str = new String("abc");
    

二、软引用

  • 软引用用于关联一些还有用但并非必需的对象,对于软引用关联着的对象,当内存空间充足时,GC 就不会回收它;当内存空间不足时,GC 就会回收它

  • 软引用可以用来实现内存敏感的高速缓存

  • 软引用可以和引用队列 ReferenceQueue 联合使用

  • 在 JDK2 之后,提供了 SoftReference 类来实现软引用

  • 举例说明

    public class SoftReferenceTest {
    
        public static void main(String[] args) {
            int count = 5;
            List<SoftReference> references = new ArrayList<>(count);
            // 实例化5个TestObject对象放入references中
            IntStream.range(0, count).forEach(i -> references.add(new SoftReference<>(new TestObject("TestObject " + i))));
            // 打印references中的所有对象
            references.forEach(softReference -> {
                Object obj = softReference.get();
                if (obj == null) {
                    System.out.println("null");
                } else {
                    System.out.println(((TestObject) obj).name);
                }
            });
        }
    }
    
    // 定义一个大对象,尽可能的占用内存
    class TestObject {
    
        public String name;
        public byte[] values;
    
        public TestObject(String name) {
            this.name = name;
            this.values = new byte[1024 * 1024 * 1024];
        }
    }
    
    // null
    // null
    // null
    // null
    // TestObject 4
    
    • 如上所示,由输出可知,前四个对象因为内存不够而被 GC 回收了

三、弱引用

  • 弱引用也是用来关联非必需对象的,但是它的强度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾回收之前,当 GC 工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象

  • 弱引用可以和引用队列 ReferenceQueue 联合使用

  • 在 JDK2 之后,提供了 WeakReference 类来实现弱引用

  • 举例说明

    public class WeakReferenceTest {
    
        public static void main(String[] args) {
            WeakReference<String> weakReference = new WeakReference<>(new String("abc"));
            System.out.println(weakReference.get());
            System.gc();
            System.out.println(weakReference.get());
        }
    }
    
    // abc
    // null
    
    • 如上所示,由输出可知,当手动调用 GC 后,字符串对象被 GC 回收了

四、虚引用

  • 虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系,一个对象是否有虚引用存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例,为一个对象设置虚引用关联的唯一目的在于可以在该对象被垃圾回收器回收时受到一个系统通知

  • 必须和引用队列 ReferenceQueue 联合使用

  • 在 JDK2 之后,提供了 PhantomReference 类来实现虚引用

  • 举例说明

    public class PhantomReferenceTest {
    
        public static void main(String[] args) throws Exception {
            ReferenceQueue<String> queue = new ReferenceQueue<>();
            PhantomReference<String> phantomReference = new PhantomReference<>(new String("abc"), queue);
            System.out.println(phantomReference.get());
            System.gc();
            // 确保phantomReference被放入queue中
            TimeUnit.SECONDS.sleep(1);
            Reference<?> reference;
            while ((reference = queue.poll()) != null){
                if (reference == phantomReference) {
                    System.out.println("我被回收了");
                }
            }
        }
    }
    
    // null
    // 我被回收了
    
    • 如上所示,由输出可知,当虚引用关联的对象被 GC 回收后,Java 虚拟机会将该虚引用放入 ReferenceQueue 中,通过判断 ReferenceQueue 中是否有值,我们可以判断出相关对象是否已被 GC 回收

    • 此外,无法通过虚引用来取得一个对象实例,因为其 get() 方法始终返回 null


五、类层次结构

在这里插入图片描述


六、归纳总结

引用类型 被垃圾回收的时间 用途 生存时间
强引用 从来不会 对象的一般状态 JVM停止运行时终止
软引用 在内存不足时 对象缓存 内存不足时终止
弱引用 在垃圾回收时 对象缓存 垃圾回收时终止
虚引用 Unkonwn Unkonwn Unkonwn
  • 强引用 (Strong Reference)

    • 最普遍的引用: Object obj = new Object()

    • Java 虚拟机宁可抛出 OutOfMemoryError 异常终止应用程序,也不会回收具有强引用的对象

    • 可以通过将对象设置为 null 来弱化引用,使其被回收

  • 软引用 (Soft Reference)

    • 用于关联有用但非必需的对象

    • 当内存空间充足时,GC 不会回收其关联的对象;当内存空间不足时,GC 会回收其关联的对象

    • 可以用来实现内存敏感的高速缓存

  • 弱引用 (Weak Reference)

    • 用于关联非必需的对象,强度比软引用更弱一些

    • 无论当前内存空间是否足够,GC 都会回收掉只被弱引用关联的对象

    • 由于 GC 线程优先级比较低,因此被弱引用关联的对象被回收的概率也不太大

    • 适用于引用偶尔被使用并且不影响垃圾收集的对象

  • 虚引用 (Phantom Reference)

    • 不会决定对象的生命周期

    • 任何时候,被虚引用关联的对象都有可能被 GC 回收

    • 跟踪对象被 GC 回收的活动,起哨兵作用

    • 必须和引用队列 ReferenceQueue 联合使用


七、参考资料

发布了106 篇原创文章 · 获赞 83 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/Goodbye_Youth/article/details/105434080
今日推荐