软引用在内存不足时才回收,弱引用每次gc都回收;二者均基于gc roots可达性分析分级判断,软引用用于内存敏感缓存,弱引用适用于依赖强引用生命周期的场景。

JVM 垃圾回收对软引用和弱引用对象的处理方式截然不同,核心区别在于“是否等待内存压力”以及“GC 触发时机”。它们不是简单地“看有没有引用”,而是由 GC 算法在标记阶段根据引用类型做分级判断。
软引用:内存不足时才回收
软引用对象在内存充足时被视为“可保留”,GC 会跳过;只有当 JVM 检测到即将发生内存溢出(比如 Eden 区填满、老年代空间紧张),才会在一次或多次 GC 中尝试回收所有仅被软引用持有的对象。
- 回收不是立即发生的——JVM 会先尝试其他回收策略(如 Minor GC、老年代担保失败后的 Full GC)
- 软引用本身是普通 Java 对象,需被强引用持有,否则软引用实例自身也会被回收
- 可通过 ReferenceQueue 捕获被回收的软引用,及时清理关联资源(如缓存键)
- 典型用途是内存敏感缓存:图片、网页内容、解析结果等,业务上允许“丢了再加载”
弱引用:每次 GC 都检查并回收
弱引用对象不等待内存压力,只要 GC 线程运行(包括 Minor GC 和 Full GC),就会把所有仅被弱引用持有的对象标记为可回收,并在本次 GC 清理掉。
- 无论堆内存是否充足,只要对象只被弱引用指向,就属于“即死”状态
- WeakHashMap 的底层就是靠弱引用来实现 key 的自动失效:key 被回收后,对应 Entry 在下一次扩容或迭代时被清理
- 适合生命周期依赖于外部强引用的场景,比如监听器注册、临时元数据映射
关键细节:它们都绕不开 GC Roots 可达性分析
JVM 不是单独扫描“软/弱引用对象”,而是在可达性分析过程中,对引用链上的引用节点做类型识别:
- 强引用构成的路径 → 对象一定存活
- 软引用路径 → 标记为“软可达”,后续按内存状况决定是否清除
- 弱引用路径 → 标记为“弱可达”,本次 GC 直接清空
- 虚引用路径 → 不影响对象存活,仅用于入队通知
实际行为受 GC 算法和参数影响
例如 G1 收集器在 Mixed GC 阶段会主动扫描老年代中的软/弱引用;而 Serial 或 Parallel GC 则在每次 Full GC 时统一处理。另外,-XX:SoftRefLRUPolicyMSPerMB 参数可调整软引用的“老化策略”,默认每兆空闲堆内存保留软引用对象 1000 毫秒。










