Java JVM 5-对象的四大引用方式

 在JDK1.2以前,Java对引用的定义是 :

如果引用类型的数据中存储的数值代表的是另一块内存的起始地址,就称这块内存代表着一个引用。

 这种定义有些狭隘,一个对象在这种定义下只有被引用或者没有被引用两种状态。我们希望能描述这一类对象 :

当内存空间还足够时,则能保存在内存中;如果内存空间在进行垃圾回收后还是非常紧张,则可以抛弃这些对象。很多系统中的缓存对象都符合这样的场景。

1. 引用的分类

 在JDK1.2之后,Java对引用的概念做了扩充,将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)四种,这四种引用的强度依次递减。

1.1 强引用

 >强引用指的是在程序代码之中普遍存在的,类似于”Object obj = new Object()”这类的引用,只要强引用还存在,垃圾回收器永远不会回收掉被引用的对象实例,哪怕内存不够,程序宁可抛出OOM,即宁为玉碎不为瓦全。

/**
 * JVM运行参数: -XX:+PrintGC 打印GC日志
 * -Xms10m -Xmx10m 设置堆大小为10m
 * @author xucc
 */

public class Test {

    public static void main(String[] args) {
        // 占位
        byte[] data = new byte[1*1024*1024];
        new Test().OOM();
    }

    public void OOM() {
        // 创建一个8m的数组对象
        byte[] bytes = new byte[8*1024*1024];
    }
}

运行结果

 不过要注意的是,当OOM()运行完之后,Test和bytes都已经不存在了,所以它们指向的对象都会被JVM回收。
  
 如果想中断强引用和某个对象之间的关联,可以显示地将引用赋值为null,这样一来的话,JVM在合适的时间就会回收该对象。

1.2 软引用

软引用是用来描述一些还有用但是不是必须的对象。对于软引用关联着的对象,在系统将要发生内存溢出之前,会把这些对象列入回收范围之中进行第二次回收。如果这次回收还是没有足够的内
存,才会抛出内存溢出异常。

 如果一个对象具有软引用,内存空间足够,垃圾回收器就不会回收它;

 如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。

 软引用可用来实现内存敏感的高速缓存,比如网页缓存、图片缓存等。使用软引用能防止内存泄露,增强程序的健壮性。

 在JDK1.2之后,提供了SoftReference类来实现软引用。

public class SoftReference<T> extends Reference<T>

 SoftReference的特点是它的一个实例保存对一个Java对象的软引用, 该软引用的存在不妨碍垃圾收集线程对该Java对象的回收。

 也就是说,一旦SoftReference保存了对一个Java对象的软引用后,在垃圾线程对 这个Java对象回收前,SoftReference类所提供的get()方法返回Java对象的强引用。

 另外,一旦垃圾线程回收该Java对象之 后,get()方法将返回null。

 举个栗子:

import java.lang.ref.SoftReference;

/**
 * JVM运行参数: -XX:+PrintGC 打印GC日志
 * -Xms10m -Xmx10m 设置堆大小为10m
 * @author xucc
 */

public class Test {

    public static void main(String[] args) {
        byte[] bytes = new byte[6*1024*1024];
        SoftReference byteSoftRef = new SoftReference(bytes);
        // 现在,对于这个字节数组有两种引用方式,随后,我们将它的强引用结束掉,现在,就变成了一个彻底的软引用对象
        bytes = null;

        byte[] bytes1 = new byte[5*1024*1024];
        // System.gc();
    }
}

运行结果:

运行结果

1.3 弱引用

弱引用也是用来描述非必需对象的。但是它的强度要弱于软引用。被弱引用关联的对象只能生存到下一次垃圾回收发生之前。当垃圾回收器开始进行工作时,无论当前内容是否够用,都会回收掉只被弱引用关联的对象。在JDK1.2之后提供了WeakReference类来实现弱引用。

public class WeakReference<T> extends Reference<T>

 看下面的例子:

import java.lang.ref.WeakReference;

/**
 * JVM运行参数: -XX:+PrintGC 打印GC日志
 * -Xms10m -Xmx10m 设置堆大小为10m
 * @author xucc
 */

public class Test {
    public static void main(String[] args) {
        WeakReference byteWeakReference = new WeakReference(new byte[2*1024*1024]);
        System.gc();
    }
}

运行结果:

运行结果

1.4 虚引用

 虚引用也被称为幽灵引用或者幻影引用,它是最弱的一种引用关系。一个对象是否有虚引用的
存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。

 为一个对象设置虚引用的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。在JDK1.2之后,提供了PhantomReference类来实现虚引用。

public PhantomReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
}

 要注意的是,虚引用必须和引用队列关联使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会把这个虚引用加入到与之 关联的引用队列中。

public class ReferenceQueue<T>

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

猜你喜欢

转载自blog.csdn.net/weixin_40739833/article/details/80715637
今日推荐