强引用不被GC回收,即使内存溢出;软引用在OOM前才回收,适合内存敏感缓存;弱引用每次GC都可能回收,用于防哈希表泄漏;虚引用仅用于回收通知,无法取值。

强引用不会被GC回收,哪怕内存溢出也不行
只要对象还被 Object obj = new Object() 这种方式直接持有,JVM 就认定它「必须活着」。哪怕堆快爆了,GC 也绝不会动它——宁可抛 OutOfMemoryError,也不会回收强引用对象。
常见错误现象:缓存用 HashMap 存大量对象,key 是强引用,导致对象长期无法释放,最终 OOM。
- 使用场景:日常绝大多数变量、字段、方法参数都属于强引用,无需额外操作
- 性能影响:零成本,但也是内存泄漏最常见源头
- 容易踩的坑:
static字段持强引用 + 长生命周期类(如 Servlet、Spring Bean),极易造成 ClassLoader 泄漏
软引用在内存不足时才回收,适合做内存敏感缓存
SoftReference 的回收时机由 JVM 自主决定,但有个隐含规则:只有在即将发生 OutOfMemoryError 前,GC 才会清理它。不是“内存一紧张就收”,而是“快撑不住了才动手”。
使用场景:图片缓存、JSON 解析结果缓存等——希望常驻内存,但又不能抢走关键资源。
立即学习“Java免费学习笔记(深入)”;
- 参数差异:
SoftReference<t>(referent)</t>构造简单,但注意它不支持引用队列自动清理逻辑(得自己轮询queue.poll()) - 兼容性影响:Java 1.2+ 全支持,无风险;但 Android 上部分低版本 GC 策略更激进,软引用可能比预期早回收
- 容易踩的坑:把
SoftReference当成“弱一点的强引用”来用,结果发现缓存命中率极低——它本就不保证驻留时间
弱引用只要发生 GC 就可能消失,适合解决哈希表键泄漏
WeakReference 的回收门槛最低:下一次 GC(哪怕是 Young GC)就可能被清掉。它和 WeakHashMap 底层共用同一套机制——key 是弱引用,value 没有被其他强引用持有时,整条 Entry 就会被移除。
常见错误现象:WeakHashMap 里 key 对象被回收后,对应 value 却还在内存中——其实是 value 被其他地方强引用了,不是 WeakHashMap 失效。
- 使用场景:监听器注册、ThreadLocal 的 key、临时映射关系(如 class → proxy 实例)
- 性能影响:每次访问需判空(
ref.get() != null),否则 NPE;但无额外 GC 开销 - 容易踩的坑:误以为
WeakReference能自动清理 value——它只管 referent,value 得自己处理生命周期
虚引用唯一作用是接收对象被回收的通知,不能取值
PhantomReference 是最特殊的:它的 get() 方法永远返回 null,你拿不到对象本身。它存在的唯一意义,是当对象进入 F-Queue 后,JVM 会把它加入关联的 ReferenceQueue,让你能感知“这东西刚被回收”。
使用场景:替代 finalize() 做资源清理(比如关闭堆外内存、释放文件句柄),因为 finalize() 已被弃用且不可靠。
- 参数差异:构造必须传
ReferenceQueue,否则毫无意义;且必须配合队列轮询使用 - 容易踩的坑:直接调
phantomRef.get()想取对象——结果永远是null;或忘记在队列中 poll 后调clear(),导致 Reference 对象自身堆积 - 注意点:虚引用对象在被回收前,必须已结束 finalize(如果有的话),所以它比弱/软引用更晚触发
四种引用真正难的不是定义,而是判断「这个业务该用哪一种」——比如缓存,选软引用还是弱引用,取决于你更怕 OOM 还是更怕频繁重建;而虚引用一旦用错,就等于没写清理逻辑。










