软引用适合构建内存敏感型缓存,JVM堆紧时自动回收防OOM;需判空、懒重建、配合ReferenceQueue异步清理,并调优-XX:SoftRefLRUPolicyMSPerMB参数。

软引用适合构建内存敏感型变量缓存——它不锁死对象生命周期,JVM 在堆内存趋紧时自动回收,既保留缓存收益,又防 OOM。但不能把它当“稳态缓存”用,每次访问都得判空、失效后要能重建,且需配合清理机制避免 Map 膨胀。
缓存结构设计:轻量+线程安全+带时间感知
别直接用 Map 简单封装:
- 用
ConcurrentHashMap替代普通 HashMap,避免并发写冲突 -
CacheEntry包含SoftReference+long lastAccessTime,用于模拟 LRU 行为(SoftReference 本身不记录访问顺序) - 构造
SoftReference时传入ReferenceQueue,为异步清理打基础
读写逻辑:必判空、防悬挂、支持懒重建
get 操作不是取值,而是“尝试命中+兜底加载”:
- 先从 Map 获取
CacheEntry,再调entry.ref.get() - 若返回
null,说明已被回收 → 触发业务逻辑重新生成 value,并新建SoftReference写回 - 不要把
ref.get()结果长期赋给强引用变量(如静态字段或长生命周期对象),否则缓存失效机制就形同虚设
失效清理:主动轮询队列,不等 GC 扫尾
ReferenceQueue 不会自动清 Map,必须你来驱动:
- 在
put()或高频get()入口轻量调用queue.poll() - 拿到已回收的
SoftReference后,通过自定义 key 提取方式(比如让CacheEntry持有 key)从 Map 中移除对应条目 - 避免使用
remove()阻塞等待,非阻塞poll()更适合生产环境
JVM 参数微调:平衡存活与及时释放
默认策略(-XX:SoftRefLRUPolicyMSPerMB=1000)对多数服务偏激进:
- 若缓存对象较大、重建成本高,可设为
3000~5000,延长软引用平均存活窗口 - 注意该参数仅对 Parallel 和 G1 GC 生效;ZGC/Shenandoah 下软引用会在下次 GC 时立即回收
- 不要无限制拉高数值,比如设成 60000,可能拖慢老年代回收节奏,反致 OOM










