Java中的四种引用

更新时间:2020-08-14 10:04:59 点击次数:1071次
Java中的四种引用
Java中有四种引用类型:强引用、软引用、弱引用、强引用

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

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

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

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中。

运行结果

[外链图片转存中…(img-kVGMRh0s-1596903475719)]

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

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

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

本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是一个个人学习交流的平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽,造成漏登,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

回到顶部
嘿,我来帮您!