参考资料
- https://juejin.cn/post/7123853933801373733
在 Java 中,引用类型分为四种:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)。这些引用类型的主要区别在于它们如何与垃圾回收器(GC)进行交互。
1. 强引用(Strong Reference)
定义:强引用是 Java 中最常见的引用类型。只要一个对象有强引用存在,垃圾回收器就不会回收这个对象。
示例:
String strongRef = new String("Hello, World!");
解释:
- 在这段代码中,
strongRef
是一个指向String
对象的强引用。只要strongRef
变量存在,并指向String
对象,垃圾回收器就不会回收它。
2. 软引用(Soft Reference)
定义:软引用是一个在内存不足时才会被垃圾回收的引用。它通常用于实现缓存,当内存不足时,垃圾回收器会回收这些被软引用指向的对象。
示例:
import java.lang.ref.SoftReference;String str = new String("This is a soft reference example");
SoftReference<String> softRef = new SoftReference<>(str);// 使强引用失效
str = null;
解释:
softRef
是指向String
对象的软引用。- 一旦
str
置为null
,强引用消失,该对象仅通过softRef
保持可达状态。 - 当 JVM 发现内存不足时,它可能会回收
softRef
指向的对象。
3. 弱引用(Weak Reference)
定义:弱引用是一个比软引用更弱的引用类型。弱引用的对象在垃圾回收过程中,只要发现弱引用,不管当前内存是否足够,都会被回收。
示例:
import java.lang.ref.WeakReference;String str = new String("This is a weak reference example");
WeakReference<String> weakRef = new WeakReference<>(str);// 使强引用失效
str = null;
解释:
weakRef
是指向String
对象的弱引用。- 一旦
str
置为null
,强引用消失,该对象仅通过weakRef
保持可达状态。 - 在下次垃圾回收时,无论内存是否充足,垃圾回收器都会回收
weakRef
指向的对象。
4. 虚引用(Phantom Reference)
定义:虚引用(或幻影引用)是最弱的一种引用类型。一个对象不能通过虚引用获得其引用对象。虚引用主要用于跟踪对象被垃圾回收的过程。当一个对象只剩下虚引用时,在下一次垃圾回收时会被回收。同时,虚引用必须和引用队列(ReferenceQueue)一起使用。
示例:
import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;String str = new String("This is a phantom reference example");
ReferenceQueue<String> refQueue = new ReferenceQueue<>();
PhantomReference<String> phantomRef = new PhantomReference<>(str, refQueue);// 使强引用失效
str = null;// 使用队列来检查虚引用对象是否被回收
if (phantomRef.isEnqueued()) {System.out.println("Object is ready to be reclaimed by the garbage collector.");
}
解释:
phantomRef
是指向String
对象的虚引用,refQueue
是一个引用队列。- 一旦
str
被置为null
,对象仅通过phantomRef
虚引用保持“存在”,但实际上已经无法通过该引用访问对象。 - 在对象被垃圾回收后,
phantomRef
会被加入到refQueue
中,程序可以通过refQueue
得知对象已被回收。
ReferenceQueue
是 Java 中提供的一个队列,用于与软引用(SoftReference
)、弱引用(WeakReference
)、和虚引用(PhantomReference
)等引用类型一起使用,以便在对象被垃圾回收时得到通知或做相应的清理工作。
ReferenceQueue
的作用
-
跟踪被回收的对象:
ReferenceQueue
用来保存被垃圾回收器标记为可回收的引用对象。当一个对象被垃圾回收后,如果该对象的引用(软引用、弱引用或虚引用)关联了一个ReferenceQueue
,那么这个引用会被加入到ReferenceQueue
中。 -
用于清理和资源管理:通过
ReferenceQueue
,程序可以在对象被回收时执行某些清理操作,例如释放外部资源、关闭文件等。特别是虚引用(PhantomReference
)必须和ReferenceQueue
一起使用,因为虚引用的主要目的是帮助检测对象的垃圾回收状态。
ReferenceQueue
的使用场景
-
缓存管理:结合软引用和弱引用使用,在内存不足或对象无强引用的情况下,对象被垃圾回收器回收并加入到
ReferenceQueue
,可用于从缓存中移除无用数据。 -
对象的生命周期管理:对于需要明确知道对象何时被垃圾回收的场景,可以使用虚引用和
ReferenceQueue
,以便在对象被回收时执行某些特殊的清理操作。
示例:使用 ReferenceQueue
下面是一个使用 ReferenceQueue
和弱引用的简单示例:
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;public class ReferenceQueueExample {public static void main(String[] args) {// 创建一个引用队列ReferenceQueue<String> refQueue = new ReferenceQueue<>();// 创建一个字符串对象并将其封装在一个弱引用中,同时关联引用队列String str = new String("Hello, ReferenceQueue");WeakReference<String> weakRef = new WeakReference<>(str, refQueue);// 清除强引用str = null;// 手动调用垃圾回收器(这只是一个提示,GC 可能不会立即执行)System.gc();// 检查引用队列中是否有被回收的引用Reference<? extends String> refFromQueue = refQueue.poll();if (refFromQueue != null) {System.out.println("The weakly referenced object has been garbage collected and the reference is in the queue.");} else {System.out.println("The object has not been garbage collected yet.");}}
}
代码解释
-
创建引用队列:
ReferenceQueue<String> refQueue = new ReferenceQueue<>();
创建了一个ReferenceQueue
对象,用于保存被垃圾回收的引用。 -
创建弱引用:
WeakReference<String> weakRef = new WeakReference<>(str, refQueue);
创建一个指向str
的弱引用,并将其与refQueue
关联。 -
清除强引用:通过
str = null;
清除对对象的强引用,使得该对象仅被弱引用所引用。 -
手动触发 GC:调用
System.gc();
提示垃圾回收器运行。请注意,这只是一个提示,垃圾回收器不一定会立即执行。 -
检查引用队列:通过
refQueue.poll()
检查引用队列中是否有被回收的引用,如果返回非null
值,则表示对象已经被回收。
总结
- 强引用:最常见的引用类型,不会被垃圾回收。
- 软引用:在内存不足时会被回收,适用于缓存。
- 弱引用:在垃圾回收时会被回收,适用于对内存敏感的数据结构,如 WeakHashMap。
- 虚引用:不能直接访问对象内容,主要用于跟踪对象的垃圾回收情况。