JVM之垃圾回收相关引用介绍

559 阅读3分钟

这是我参与更文挑战的第 26 天,活动详情查看: 更文挑战

垃圾回收相关引用介绍

概述

JDK1.2之后,Java对引用的概念进行了扩充,把引用分为了强引用、软引用、弱引用和虚引用,这四种引用的强度逐渐减弱。

  • 强引用(StrongReference):最常见的引用方式,传统的new对象的方式就是强引用。无论在任何情况下,只要强引用的关系还在,垃圾回收器就永远不会回收被引用的对象。永远不回收
  • 软引用(SoftReference):系统将要发生内存溢出之前,会把这些对象放入回收范围中进行第二次回收。如果还是没有足够的内存才会出现OOM。内存不足即回收
  • 弱引用(WeakReference):被弱引用关联的对象只能存活到下一次垃圾回收之前。只要垃圾回收器触发,不管内存是否足够,弱引用关联的对象都会被回收。发现即回收
  • 虚引用(PhantomReference):一个对象是否有虚引用,完全不会对其生命周期造成影响,也不能通过一个虚引用获取一个对象的实例。为一个对象设置虚引用的唯一目的就是在这个对象被垃圾回收器回收时收到一个系统通知。对象回收跟踪

上面的情况都是在对象可达的情况下。

强引用

Java中最常用的一种引用,也是默认的引用类型。强引用的对象都是可触及的,垃圾回收器永远都不会回收强引用对象。对于一个普通的对象,如果没有其他引用关系,只要超过了引用的作用域或显示的把引用赋值为NULL,那就可以当作垃圾被回收。

相对的,软引用、弱引用、虚引用的对象是软可触及的、弱可触及的和虚可触及的,在一定条件下都是可悲回收的,所以,强引用时造成Java内存泄漏的主要原因之一。

强引用特点:

  • 强引用可以直接访问目标对象。
  • 强引用所指对象永远不会被回收,最终导致OOM也不会被回收。
  • 强引用可能导致内存泄漏。

软引用

软引用描述一些还有用但不是必须的对象。在被软引用关联着的对象,在内存将要溢出之前,会把这些对象放到回收范围中进行第二次回收,如果回收后内存还不够才会抛出OOM。这个内存溢出和软引用没有关系。

构造软引用的时候,可以指定一个引用队列,当软引用对象被回收时,就会加入指定的队列,通过这个对象可以跟踪对象的回收情况。

软引用通常用来实现内存敏感的缓存,比如高速缓存,如果有空闲内存,就可以暂时保留缓存,当内存不足时清理掉。

JVM会尽量让软引用存活时间长一些,迫不得已才清理。

软引用实现如下:

SoftReference<Object> sf = new SoftReference<>(new Object());

弱引用

和软引用相同,弱引用也是描述那些非必须的对象,只被弱引用关联的对象只能活到下一次垃圾回收为止,GC时,只要有弱引用,无论空间是否充足都会回收掉只被弱引用关联的对象。

但是由于垃圾回收的线程优先级较低,因此,被弱引用关联的对象可能会存活较长的时间。

和软引用相同,可以使用引用队列保存弱引用关联的对象。

弱引用实现如下:

WeakeReference<Object> wf = new WeakeReference<>(new Object());

软引用和弱引用最大的区别就是:软引用是内存不足即回收,而弱引用是发现即回收,弱引用相对软引用更容易、更快被GC回收。

虚引用

虚引用是所有引用类型中最弱的一个,一个对象是否有虚引用的存在,完全不会决定对象的生命周期。如果一个对象只有虚引用,那么它和没有引用几乎一样,随时都可能会被垃圾回收器回收。

不能单独使用,也不能通过虚引用获取来获取被引用的对象。

虚引用唯一的目的就是在于跟踪垃圾回收的过程,如在对象回收时收到一个系统通知。

虚引用必须和引用队列一起使用,创建时需要提供一个引用队列作为参数。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象后,将这个虚引用加入引用对象,以通知应用程序对象的回收情况。

由于虚引用可以跟踪对象的回收时间,因此也可以将一些资源释放的操作放在虚引用中执行和记录。

虚引用实现如下:

ReferenceQueue q = new ReferenceQueue();
PhantomReference <Object> pf = new PhantomReference<>(new Object(), q);