美文网首页程序员
Java中的这四种引用你真的了解了吗?

Java中的这四种引用你真的了解了吗?

作者: 程序员伟杰 | 来源:发表于2020-08-11 14:02 被阅读0次

前言

JDK1.2之后,把对象的引用分为四种状态,即强引用、软引用、弱引用和虚引用。这样的方式,可以更加灵活地控制对象的生命周期。

Java中的四种引用

Java中有四种引用类型:强引用、软引用、弱引用、强引用

Java中为什么要有设计这四种引用

Java的内存分配和内存回收,都不需要程序员自己负责的,都是由虚拟机负责,而虚拟机判断一个对象是否要回收,就是看是否有引用指向此对象,也就是用可行性分析

设计四种引用的目的有两个:

  1. 可以让程序员通过代码的方式决定某个对象的生命周期
  2. 有利于使用垃圾回收

强引用

强引用的表现:

Object o = new Object();

像这种主动去new一个对象的引用,就是强引用,这种对象永远不会被回收,即使内存不知,JVM只会爆OOM,也不是去回收

如果想要它被回收可以主动把强引用和对象的关联中断,也就是断掉指针

o = null

可以通过手动调用GC,看看指针断裂之后,资源会不会被回收,为了方便观察回收的情况,我这里重新写一个类,重写finalize方法

public class TestQuote {
    @Override
    protected void finalize() throws Throwable{
        System.out.println("TestQuote 被回收了");
    }
    public static void main(String[] args) {
        TestQuote testQuote = new TestQuote();
        testQuote = null;
        System.gc();
    }
}

运行结果:


软引用

先看如果创建一个软引用:

软引用就是把对象用SoftReference包裹一下,当我们需要从软引用对象获得包裹的对象,只需要get一下就好了

SoftReference<TestQuote> testQuoteSoftReference = new SoftReference<>(new TestQuote());
TestQuote testQuote = testQuoteSoftReference.get();
System.out.println(testQuote);

软引用的特点是:

当内存不足,会触发JVM的GC,如果GC后,内存还是不足,就会把软引用包裹的对象给清除,也就是当JVM的内存不足的时候,才会回收该对象。

下面模拟一下内存不足的清除状况

SoftReference<byte[]> softReference = new SoftReference<byte[]>(new byte[1024*1024*10]);
        System.out.println(softReference.get());
        System.gc();
        System.out.println(softReference.get());
        byte[] bytes = new byte[1024*1024*10];
        System.out.println(softReference.get());

这里我定义了一个软引用对象,里面包裹了byte[],byte[]占用了10M,然后又创建了10M的byte[]

然后我们需要改一个参数:

-Xmz20M

代表最大的堆内存为20M

运行结果:

可以很清楚看到手动完成GC后,软引用对象包裹的byte[]还活得好好的,但是当再创建一个10M的byte[]后,最大堆内存不够用,所以把软引用对象包裹的byte[]给清除了,如果不清除,就会抛出OOM

软引用比较合适用作缓存,当内存足够的时候,可以正常的拿到缓存,当内存不够,就会先干掉缓存,不至于马上抛出OOM

弱引用

弱引用的使用和软引用类型,只是关键字变成了WeakReference:

WeakReference<byte[]> weakReference = new WeakReference<>(new byte[1024*1024*10]);
        System.out.println(weakReference.get());

弱引用的特点是不管内存是否足够,只要发生GC,都会被回收:

WeakReference<byte[]> weakReference = new WeakReference<>(new byte[1024*1024*10]);
        System.out.println(weakReference.get());
        System.gc();
        System.out.println(weakReference.get());

运行结果:


可以看到内存还是很足够的时候,但是触发了GC,资源还是内回收了

弱引用在很多地方都有用到,比如ThreadLocal、WeakHashMap

虚引用

虚引用又被称为幻影引用

ReferenceQueue queue = new ReferenceQueue();
        PhantomReference<byte[]> reference = new PhantomReference<>(new byte[1],queue);
        System.out.println(reference.get());

虚引用的使用和上面的软引用和弱引用的区别还是挺大了,这里先不管ReferenceQueue是什么东西

直接运行

直接输出了null,这里先去看看get方法的源码:


直接返回了null,这就是虚引用的特点之一:无法通过虚引用来获取对一个对象的真实引用。

那虚引用的使用有什么意义,这里先看回创建虚引用的代码

ReferenceQueue queue = new ReferenceQueue();
        PhantomReference<byte[]> reference = new PhantomReference<>(new byte[1],queue);
        System.out.println(reference.get());

创建虚引用对象,这里除了把包裹对象传进去,还传进了一个ReferenceQueue,从名字就可以看出它是一个队列。

虚引用的特点之二就是虚引用必须与ReferenceQueue一起使用,当GC准备回收一个对象,如果发现它还有虚引用就会再回收之前,把这个虚引用加入到与之关联的ReferenceQueue中

接下来实践一下:

ReferenceQueue queue = new ReferenceQueue();
        List<byte[]> bytes = new ArrayList<>();
        PhantomReference<TestQuote> reference = new PhantomReference<TestQuote>(new TestQuote(),queue);
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                bytes.add(new byte[1024*1024*1024*1024*1024*1024*1024]);
            }
        }).start();

        new Thread(() -> {
            while (true) {
                Reference poll = queue.poll();
                if (poll != null) {
                    System.out.println("虚引用被回收了:" + poll);
                }
            }
        }).start();
        Scanner scanner = new Scanner(System.in);
        scanner.hasNext();

运行结果

第一个线程往集合里面塞数据,随着数据越来越多,肯定会发生GC。
第二个线程死循环,从queue里面拿数据,如果拿出来的数据不是null,就打印出来。

从运行结果可以看到:当发生GC,虚引用就会被回收,并且会把回收的通知放到ReferenceQueue中。

运行结果

第一个线程往集合里面塞数据,随着数据越来越多,肯定会发生GC。
第二个线程死循环,从queue里面拿数据,如果拿出来的数据不是null,就打印出来。

从运行结果可以看到:当发生GC,虚引用就会被回收,并且会把回收的通知放到ReferenceQueue中。

NIO中,就运用了虚引用管理堆外内存

最后

感谢你看到这里,看完有什么的不懂的可以在评论区问我,觉得文章对你有帮助的话记得给我点个赞,每天都会分享java相关技术文章或行业资讯,欢迎大家关注和转发文章!

相关文章

  • Java中的这四种引用你真的了解了吗?

    前言 JDK1.2之后,把对象的引用分为四种状态,即强引用、软引用、弱引用和虚引用。这样的方式,可以更加灵活地控制...

  • 2018-12-17

    震惊!超声刀原理和副作用你都了解了吗?五年后加快衰老是真的吗? 震惊!超声刀原理和副作用你都了解了吗?五年后加快衰...

  • Glide缓存模块源码分析

    在开始之前,我们先了解Java中的四种引用和ReferenceQueue,为什么要了解这些知识呢?大家都知道Gli...

  • Java基础:Java的四种引用

    在Java基础:java虚拟机(JVM)中,我们提到了Java的四种引用。包括:强引用,软引用,弱引用,虚引用。这...

  • 4种权限修饰符区别

    java中权限修饰符有:public、protected、default(缺省)、private这四种,不写的话,...

  • java8-新的日期API

    背景 java的日期和时间API设计不理想,java8引入新的时间和日期API就是为了解决这个问题。 java8引...

  • JVM虚拟机读书笔记

    Java VM Runtime Area Java中四种引用: - 强引用(Strong Reference): ...

  • Android使用LeakCanary检测内存泄漏

    Java四种引用 在Java中,有四种不同的引用类型,分别是强引用(Strong Reference)、软引用(S...

  • 访问控制权限

    Java支持四种控制权限public、protected、default、private,这四种访问控制权限的特点...

  • java的四种引用类型

    java有四种引用类型 StrongReference 强引用,最普通的引用,虚拟机即使抛出OOM也不会回收此类引...

网友评论

    本文标题:Java中的这四种引用你真的了解了吗?

    本文链接:https://www.haomeiwen.com/subject/unxjdktx.html