引用类型

在 JDK 1.2 之后,Java 对引用的概念进行了扩充,将引用分为了:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)4 种,这 4 种引用的强度依次减弱。

1. 强引用(StrongReference)

当一个实例对象被强引用时,垃圾回收器就不会回收该对象,内存不足时抛出 OutOfMemeryError 异常也不会回收强引用对象。
测试案例:

  1. // 定义当前内存 -Xms2M -Xmx3M
  2. // 当内存使用为 1M 时,程序运行正常
  3. byte[] buff1 = new byte[1024 * 1024];
  4. // 当内存使用为 2M 时,程序运行正常
  5. byte[] buff2 = new byte[1024 * 1024];
  6. // 当内存使用为 3M 时,内存溢出
  7. byte[] buff3 = new byte[1024 * 1024];

image.png

2. 软引用(SoftReference)

当实例对象只具有软引用时,内存不足的时候垃圾回收器会将软引用对象回收。
测试案例:

List<SoftReference<byte[]>> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
    SoftReference<byte[]> sr = new SoftReference<>(new byte[1024 * 1024]);
    list.add(sr);
}
for (SoftReference<byte[]> reference : list) {
    System.out.println("获取的引用数据:" + reference.get());
}

image.png
使用场景:缓存,图片编辑器

3. 弱引用(WeakReference)

只要触发了垃圾回收,无论内存空间是否充足,都会将弱引用对象回收。
测试案例:

WeakReference<byte[]> wr = new WeakReference<>(new byte[1024 * 512]);
System.out.println("清除前数据:" + wr.get());
// 通知GC清除垃圾
System.gc();
System.out.println("清除后数据:" + wr.get());

image.png

执行 System.gc() 方法只通知JVM回收垃圾,但是并不是立刻执行垃圾回收

使用场景:WeakHashMap(键失去强引用后,触发GC时键和值将会回收移除),ThreadLocalMap防止内存泄漏

4. 虚引用(PhantomReference)

只要实例对象被回收,虚引用对象就会被放入引用队列中,虚引用对象必须配合引用队列使用。
虚引用之所以需要配合引用队列是因为,虚引用本身无法获取到引用的对象,只能感知对象被回收,当对象被回收后,虚引用本身就没意义了。当有引用队列以后,虚引用对象被加入到队列后,就可以知道虚引用对象失去了虚引用,就可以得知对象被回收,然后进行对象回收后的操作。
测试案例:

ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
PhantomReference<byte[]> pr = new PhantomReference<>(new byte[1024 * 512], queue);
System.out.println("获取的引用数据:" + pr.get());
System.gc();
System.out.println("队列中的虚引用:" + queue.poll());

image.png
使用场景:对象销毁之前操作,资源释放

5. 引用队列(ReferenceQueue)

    软引用本身也是一个 Java 对象,当软引用对象被回收以后本身已经没有作用了,调用 get() 方法返回 null ,所以需要一个合适的清除机制,避免大量软引用对象的创建导致内存泄漏。在 Java 中提供了 ReferenceQueue 引用队列,**与软引用、弱引用以及虚引用一起配合使用,用作保存被清除引用的 Reference 对象**,当 Reference 对象中引用被清除后加入队列。<br />        在 SoftReference 对象构造方法中添加引用队列,调用 ReferenceQueue 对象的 poll() 方法时,会返回被清除软引用的 SoftReference 对象,并从队列中移除。<br />测试案例:
List<SoftReference<byte[]>> list = new ArrayList<>();
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
for (int i = 0; i < 5; i++) {
    SoftReference<byte[]> sr = new SoftReference<>(new byte[1024 * 512], queue);
    System.out.println("所创建的软引用:" + sr);
    list.add(sr);
}
Reference<? extends byte[]> reference;
while ((reference = queue.poll()) != null) {
    System.out.println("被清除的软引用:" + reference);
}

image.png