java中的四种引用类型(强引用,软引用,弱引用,虚引用)

什么是引用?

引用的本质是指针常量,对于我们这篇文章来说,我们只需要知道引用是一种特殊的指针就行了。
下面是Java中典型的声明和创建对象的代码,其中o就是我们的引用。前面的Object是引用类型,后面的new Object()是Java对象。o指向了new Object(),也就是o引用了new Object()对象。

Java中的引用类型有哪几种?

强引用:就是普通的引用,内存溢出抛异常,垃圾回收器也不会回收

软引用:内存不够时会被垃圾回收器回收

弱引用:垃圾回收器扫描到就会回收

虚引用:任何时候都可能被回收,虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。  

        不同的引用,主要在垃圾回收时有区别,一般情况下都是使用强引用  

强引用 

        强引用“强”在哪里?如果我们不手动将引用设置为null,gc是不会回收强引用的,即使内存不够也不会回收被强引用的对象,这时候会抛OOM异常。这样的好处是对象更加“稳定”,只要应用还在运行,强引用对象可以一直存活。想象一下如果你刚创建的对象还没执行完他的任务就因为内存不够而被gc回收了,这是多么可怕的场景。强引用也会带来问题,那就是可能造成内存泄漏。后面会继续介绍内存泄漏的细节。
        如果我们手动的将强引用设置为null,那么gc就会认为不存在引用,就会回收。
在Java的Object类有一个finalize方法,当对象被gc回收的时候,会调用这个方法。可以利用这个方法来观察对象是否被gc回收。

public class M {
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize");
    }
}
public class T01_NormalReference {
    public static void main(String[] args) throws IOException {
        M m = new M();
        m = null;
        System.gc();
        System.in.read();
    }
}

输出:

finalize

但m被设置为null的时候,gc确实能回收我们的对象。

软引用(SoftReference)

        事实上引用类型可以按引用强度来划分,软引用就是相对强引用弱一点的引用。
        Java将软引用封装为SoftReference类。软引用的特点是当内存不够的时候,gc会回收软引用的对象。这样就不容易造成OOM。下面的代码就是一个软引用的例子。我们new了一个10M大小的数组。并且用SoftReference包装,用这么大的数组是为了模拟OOM,后面会用到。

 SoftReference<byte[]> sr=new SoftReference<>(new byte[10*1024*1024]);

        现在我们先看下软引用的结构。如下图所示,注意sr这个引用是强引用,内部会执行类似下面的代码,这里的byteArr变量也是强引用。软引用指的是下图虚线的部分,也就是SoftReference内部有个指向我们new的数组的指针。如下图SR value才是我们的软引用。至于SR ref为什么能够实现软引用的功能,这个是JVM的事情,我们不需要关心。

下面的例子模拟内存不足的时候gc会回收软引用对象。可以通过下面的JVM参数将内存大小设置为20M。在IDEA里面可以这样设置

 

         前两次调用get方法的时候都能够获取到对象,因为这时候内存足够,当我们执行byte[] b=new byte[1010241024]这行代码的时候,又创建了一个12M的数组,加上虚拟机本身也会占用一些内存,所以这时候已经内存溢出了,但没有报OOM异常,因为虚拟机执行gc发现有软引用,就把软引用的10M对象给回收了,这样内存就又够用了,但执行第三个get方法的时候返回null,因为软引用对象已经被gc回收。这时候我们又创建了一个12M的数组byte[] b =new byte

[12 10241024]。这时候存在两个强引用类型的数组,总大小为20M加上虚拟机自身占用的内存,直接导致OOM异常。

public class T02_SoftReference {
    public static void main(String[] args) {
        SoftReference<byte[]> m = new SoftReference<>(new byte[1024*1024*10]);
        //打印m指向谁
        System.out.println(m.get());
        //回收一下内存
        System.gc();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(m.get());


        byte[] b = new byte[1024*1024*12];

        System.out.println(m.get());
    }
}

输出:

[B@4554617c
[B@4554617c
null

弱引用(WeakReference)

        弱引用的强度就更弱了。只要对象被弱引用包裹,不管内存够不够,gc只要发现有弱引用,马上回收。Java中用WeakReference类表示弱引用。下面的代码,并没有内存不足的情况,只要gc执行了,弱引用马上就会被回收。

/**
 * 弱引用遇到gc就会被回收
 */
public class T03_WeakReference {

    public static void main(String[] args) {
        WeakReference<M> m = new WeakReference<>(new M());

        System.out.println(m.get());

        System.gc();

        System.out.println(m.get());
    }
}

输出:

com.xx.M@4554617c
null
finalize

虚引用

        虚引用在Java中用PhantomReference类表示。属于最弱的一种引用,gc随时可以回收虚引用。看起来和弱引用很像。不过我们基本不需要关系这个引用。虚引用对于一般的应用开发来说是用不到的。对于开发者来说,最重要的是弱引用。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值