理解Java的强引用、软引用、弱引用和虚引用

Java中的强引用、软引用、弱引用、虚引用

前言

学过Java的同学可定听说过Java中的强引用、软引用、弱引用、虚引用,那么这四种引用再Java开发中有什么作用呢?引用之间又有什么区别?

正文

1. 强引用(StrongReference)

强引用是我们平常使用最多的引用,它的特性是如果一个对象具有强引用,那么垃圾回收器不会回收它。当内存空间不足时,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用对象来解决内存不足的问题。

Object o = new Object() // 类似于这样的都是强引用

当我们需要垃圾回收器回收这个对象时,我们可以通过一下方法:

o = null;

此时Object()就没有引用指向它,当垃圾回收器执行任务时,Object()就会被回收。

在一个方法的内部有一个强引用,这个引用保存在Java中,而真正的引用内容(Object)保存在Java中。 当这个方法运行完成后,就会退出方法栈,则引用对象的引用数0,这个对象会被回收。

但是如果强引用的对象是全局变量时,那么就需要在不用时将对象赋值为null,因为强引用不会被垃圾回收。

2. 软引用(SoftReference)

软引用的特性是指:当一个对象具有软引用时,如果在内存充足的情况下,垃圾回收器不会回收它的。但是如果内存不充足,这个时候当垃圾回收器执行任务时,就会将软引用的对象回收掉。

SoftReference<byte[]> sr = new SoftReference<>(new byte[1024*1024*10]); // 定义一个10m空间的byte数组

这里需要强调一点:

sr = new SoftReference<>(); 

这个引用是强引用的,只不过在这个对象里面软引用了一个byte数组。

我们通过下面的一段代码来看看软引用的特性是否正确:

在运行环境前我们先在VM options设置堆内存大小为20m

-Xmx20m
public class Main {
    public static void main(String[] args) {
        // 定义一个10m空间的byte数组,用软引用
        SoftReference<byte[]> sr = new SoftReference<>(new byte[1024 * 1024 * 10]);
        // 使用get()方法可以得到软引用对象
        System.out.println(sr.get());
        // 进行垃圾回收
        System.gc();
        // 延时等待
        try {
            Thread.sleep(3_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 再次打印软引用对象
        System.out.println(sr.get());
        // 定义一个12m对象
        byte[] b = new byte[1024 * 1024 * 12];
        // 再次打印软引用对象
        System.out.println(sr.get());
    }
}
结果:
    [B@1b6d3586
	[B@1b6d3586
	null

当加入一个12m的byte数组时,因为此时堆内存中已经有了个10m的数组,而堆内存大小为20m,堆内存空间不够,这就导致了软引用对象的释放。因此第三次打印时显示为null。

了解了什么是软引用,那么它的作用是什么呢? 其实软引用的作用一般用来实现内存敏感的高速缓存。例如:我们访问一张图片时,就可以用软引用指向它。这样的好处是,当我们下次访问时就可以快速的拿到这张图片,并且当内存空间不足时可以立马释放掉。这样既可以快速访问,又可以自动释放掉,起到了很好的缓存作用。

3. 弱引用(WeakReference)

弱引用软引用的区别在于:只具有弱引用的对象拥有更短暂生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定很快发现那些只具有弱引用的对象。

为了验证这一特性,直接上代码:

public class Main {
    public static void main(String[] args) {
        // 定义一个10m空间的byte数组,用弱引用
        WeakReference<byte[]> wr = new WeakReference<>(new byte[1024 * 1024]);
        // 打印一下
        System.out.println(wr.get());
        // 进行垃圾回收
        System.gc();
        // 延时等待
        try {
            Thread.sleep(3_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 再次打印一下
        System.out.println(wr.get());
    }
}
结果:
    [B@1b6d3586
	null

结果很明显,当一次垃圾回收器执行任务后,弱引用对象就被清空了。

那么弱引用一般用于哪里呢?其实,在ThreadLocal中就使用到了弱引用,可以去了解了解。

4. 虚引用(PhantomReference)

虚引用一般我们日常开发中用的不多,它的特性是无法get()到虚引用对象,垃圾回收器直接回收。

一般使用在Java内存引用系统内存,或者用来跟踪对象被垃圾回收器回收的活动。

虚引用主要用来跟踪对象被垃圾回收器回收的活动。 虚引用软引用弱引用的一个区别在于:

虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。

程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要进行垃圾回收。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

总结

引用类型被垃圾回收时间用途生存时间
强引用从来不会对象的一般状态JVM停止运行时终止
软引用当内存不足时对象缓存内存不足时终止
弱引用正常垃圾回收时对象缓存垃圾回收后终止
虚引用正常垃圾回收时跟踪对象的垃圾回收垃圾回收后终止

引用:

理解Java的强引用、软引用、弱引用和虚引用

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值