简谈 JVM 中的几种引用

Java 的垃圾回收算法一文中,我们知道 JVM 是根据一个对象有没有被引用来判断要不要对其进行垃圾回收的。但是,如果我们为了提升垃圾回收的效率,想要再把垃圾回收的条件更细化一些,比如只在内存非常紧张的时候才回收某些对象,那么光靠一个粗略的 “引用”,就显得心有余而力不足了。所以,在 JDK 1.2 版本之后,Java 扩充了引用的概念,将其扩充成了强引用软引用弱引用虚引用四个更细化的概念。

本文将参考《深入理解 Java 虚拟机 (第 3 版)》中再谈引用一节,简述一下这四种引用的概念,以及被引用的对象何时会被垃圾回收器回收。

强引用 (Strongly reference)

强引用是最传统的 “引用” 的定义,指在代码中普遍存在的引用赋值,比如 Object obj = new Object()。不论在任何情况下,只要强引用关系存在,那么垃圾回收器就永远不会回收掉被引用的对象。

软引用 (Soft reference)

软引用是用来描述一些还有用,但非必须的对象。只被软引用关联着的对象,在系统将要发生内存溢出异常之前,会把这些对象纳入回收范围进行第二次回收,如果在回收之后仍没有足够的内存,才会抛出内存溢出异常。在 JDK 1.2 版本之后提供了 SoftReference 类来实现软引用。

软引用对象可以用在类似缓存的场景中,比如在一个图片编辑器中,应用可以将用户打开的文件读入一个软引用对象。

如果要创建一个软引用对象,那么可以使用如下代码:

1
SoftReference<String> stringSoftReference = new SoftReference<>("string");

弱引用 (Weak reference)

弱引用也是用来被描述非必须的对象,但它的强度比软引用要更弱一些。被弱引用关联的对象只能生存到下一次垃圾回收发生时。当垃圾回收器开始工作后,无论当前剩余内存是否足够,被弱引用关联的对象都会被回收掉。在 JDK 1.2 版本之后提供了 WeakReference 类来实现弱引用。

弱引用常见于一些集合类中,尤其在哈希表中。因为哈希表的接口允许用户使用任何 Java 对象作为 key 来使用,而当一个键值被存入哈希表后,哈希表本身就有了对这些键和值的引用。如果这些引用是强引用,那么只要这个哈希表对象存活,哈希表关联的键和值也就永远不会被回收。如果这个哈希表同时又包含了大量的对象,那么就可能会长时间占用服务器的大量内存。这类问题的解决办法就是使用弱引用来关联这些对象,比如使用 WeakHashMap

如果要创建一个弱引用对象,那么可以使用如下代码:

1
WeakReference<String> stringWeakReference = new WeakReference<>("string");

虚引用 (Phantom reference)

虚引用也叫 “幽灵引用” 或 “幻影引用”,是最弱的一种引用。一个对象是否有虚引用存在,完全不会对其生存时间构成影响,同时用户也无法通过一个虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被回收时收到一个系统通知。在 JDK 1.2 版本之后提供了 PhantomReference 类来实现虚引用。

[^1]: Java 强软弱虚引用介绍及使用场景
[^2]: java 中四种引用类型