Java中的强引用、软引用、弱引用和虚引用详解
字数 958 2025-11-07 22:15:37
Java中的强引用、软引用、弱引用和虚引用详解
在Java中,引用类型决定了对象与垃圾回收器(GC)之间的互动方式。除了常见的强引用,Java还提供了软引用、弱引用和虚引用三种特殊引用类型,它们对应不同的垃圾回收策略。
一、强引用(Strong Reference)
强引用是最常见的引用类型,通过new关键字创建的对象默认都是强引用。
Object obj = new Object(); // obj就是强引用
特点:
- 只要强引用存在,垃圾回收器就永远不会回收被引用的对象
- 当内存不足时,JVM会抛出OutOfMemoryError而不是回收强引用对象
- 显式断开引用:
obj = null;
二、软引用(Soft Reference)
软引用用来描述一些还有用但非必需的对象。
SoftReference<Object> softRef = new SoftReference<>(new Object());
Object obj = softRef.get(); // 获取引用的对象
特点:
- 在内存充足时,软引用对象不会被回收
- 当内存不足时,这些对象会被垃圾回收器回收
- 适合用于实现内存敏感的缓存
内存回收过程:
- 第一次GC后内存仍然不足 → 回收软引用对象
- 回收后如果内存仍然不足 → 抛出OutOfMemoryError
三、弱引用(Weak Reference)
弱引用比软引用的生命周期更短。
WeakReference<Object> weakRef = new WeakReference<>(new Object());
Object obj = weakRef.get(); // 可能返回null
特点:
- 无论内存是否充足,只要发生垃圾回收,弱引用对象就会被回收
- 通过
get()方法获取对象时,可能返回null - 适合用于实现规范映射(如WeakHashMap)
四、虚引用(Phantom Reference)
虚引用是最弱的一种引用关系,无法通过虚引用获取对象实例。
ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantomRef = new PhantomReference<>(new Object(), queue);
Object obj = phantomRef.get(); // 总是返回null
特点:
- 虚引用必须与引用队列(ReferenceQueue)联合使用
get()方法总是返回null- 唯一作用:对象被回收时收到系统通知
- 虚引用对象被回收前,会放入关联的引用队列中
五、引用队列(ReferenceQueue)的作用
引用队列用于跟踪引用对象的状态变化:
ReferenceQueue<Object> queue = new ReferenceQueue<>();
WeakReference<Object> weakRef = new WeakReference<>(new Object(), queue);
// 监控引用队列
new Thread(() -> {
try {
Reference<?> ref = queue.remove();
System.out.println("对象已被回收");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
六、实际应用场景对比
-
软引用适用场景
- 图片缓存、网页缓存
- 需要自动清理的大对象缓存
-
弱引用适用场景
- WeakHashMap的键引用
- 临时性的对象监听器
- 避免内存泄漏的辅助数据结构
-
虚引用适用场景
- 精细化的资源清理
- 对象回收的监控和日志记录
- 替代finalize()方法进行资源释放
七、完整示例演示
public class ReferenceExample {
public static void main(String[] args) {
// 软引用示例
SoftReference<byte[]> softRef = new SoftReference<>(new byte[1024 * 1024]);
System.out.println("软引用对象:" + softRef.get());
// 弱引用示例
WeakReference<byte[]> weakRef = new WeakReference<>(new byte[1024]);
System.gc(); // 触发GC
System.out.println("弱引用对象:" + weakRef.get()); // 可能为null
// 虚引用示例
ReferenceQueue<byte[]> queue = new ReferenceQueue<>();
PhantomReference<byte[]> phantomRef = new PhantomReference<>(new byte[1024], queue);
System.gc();
System.out.println("虚引用对象:" + phantomRef.get()); // 总是null
}
}
理解这四种引用类型的关键在于掌握它们与垃圾回收器的交互方式,从而在不同场景下合理管理内存,避免内存泄漏的同时优化程序性能。