1. 概述

本文将快速介绍Java中的软引用(Soft References)。我们会解释它的概念、使用场景以及如何创建和使用它。

2. 什么是软引用?

软引用对象(或称为软可达对象)在内存不足时会被垃圾回收器清除。核心特征是:软可达对象没有任何强引用指向它

当垃圾回收器(GC)工作时,会遍历堆内存中的所有对象。GC会将引用类型的对象放入一个特殊队列中。完成堆内存检查后,GC通过清理该队列中的对象来决定哪些实例需要被回收。

不同JVM实现的具体规则可能不同,但文档明确说明:所有指向软可达对象的软引用,在JVM抛出OutOfMemoryError之前一定会被清除

⚠️ 需要注意:

  • 软引用被清除的时间点没有保证
  • 多个软引用的清除顺序也没有保证

通常,JVM实现会在清理最近创建的引用和最近使用的引用之间做选择。软可达对象在最后一次被引用后仍会存活一段时间,默认值是堆中每空闲1兆字节存活1秒。这个值可以通过 -XX:SoftRefLRUPolicyMSPerMB 参数调整,例如:

-XX:SoftRefLRUPolicyMSPerMB=2500

与弱引用相比,软引用的生命周期更长,因为它们会持续存在直到内存真的不够用。因此,当我们需要尽可能长时间地在内存中保留对象时,软引用是更好的选择。

3. 软引用的使用场景

软引用特别适合实现内存敏感的缓存,在这种场景下内存管理至关重要。

只要软引用的引用对象是强可达的(即正在被使用),该引用就不会被清除。例如,缓存可以这样设计:

  • 对最近使用的条目保持强引用
  • 让其他条目由垃圾回收器根据内存状况决定是否丢弃

✅ 典型应用场景:

  • 图片缓存
  • 大对象临时存储
  • 计算结果缓存

4. 使用软引用

在Java中,软引用通过 java.lang.ref.SoftReference 类表示。有两种初始化方式:

方式1:仅传入引用对象

StringBuilder builder = new StringBuilder();
SoftReference<StringBuilder> reference1 = new SoftReference<>(builder);

方式2:同时传入引用对象和引用队列

ReferenceQueue<StringBuilder> referenceQueue = new ReferenceQueue<>();
SoftReference<StringBuilder> reference2
 = new SoftReference<>(builder, referenceQueue);

引用队列(ReferenceQueue)的作用:当垃圾回收器决定清除某个引用对象时,会将该引用对象加入引用队列,这样我们就能感知GC的操作。

作为 java.lang.ref.Reference 的子类,SoftReference 提供了两个核心方法:

  • get():获取引用对象
  • clear():清除引用对象
StringBuilder builder1 = reference2.get();
reference2.clear();
StringBuilder builder2 = reference2.get(); // 返回null

每次操作软引用时,必须检查引用对象是否还存在:

StringBuilder builder3 = reference2.get();
if (builder3 != null) {
    // GC还没回收这个实例
} else {
    // GC已经清除了实例
}

5. 总结

本文介绍了软引用的核心概念和使用场景,并展示了如何创建和操作软引用。合理使用软引用可以在内存管理和对象缓存之间取得平衡,但需要注意其生命周期的不确定性。


原始标题:Soft References in Java | Baeldung