java垃圾回收依据对象是否可达,引用类型按强度分为强、软、弱、虚四类:强引用确保对象必须存活;软引用用于内存敏感缓存,oom前回收;弱引用在gc时立即回收,适用于weakhashmap;虚引用仅配合referencequeue实现回收通知,用于资源清理。

Java 垃圾回收对对象的处理,核心在于“是否可达”——而引用类型直接决定了对象从 GC Roots 出发是否还能被访问到。四种引用不是语法糖,而是 JVM 明确区分的生命周期控制机制,它们按强度递减排列:强 > 软 > 弱 > 虚。
强引用决定对象“必须存活”
只要栈帧里还存着变量(比如 User user = new User()),或者堆中其他对象仍通过字段持有它,这个对象就不可达回收。哪怕内存耗尽、OOM 即将发生,JVM 也宁可抛异常,绝不会动强引用对象。
- 日常绝大多数变量都是强引用,无需额外类包装
- 真正释放靠显式赋
null或自然超出作用域(如方法结束) - 容易引发内存泄漏:比如静态集合长期持有着业务对象的强引用,却不清理
软引用支撑“内存敏感缓存”
软引用对象在内存充足时保留在堆中;仅当 JVM 判定即将 OOM(例如老年代空间不足、GC 后仍无法满足分配请求)时,才会批量回收所有软引用指向的对象。
- 典型场景是图片/网页/数据的内存缓存,如 Glide、OkHttp 的响应缓存
- 使用
SoftReference<t></t>包裹对象,调用.get()获取实例(可能为null) - 可配合
ReferenceQueue监听回收事件,及时清理关联资源(如缓存索引)
弱引用用于“自动清理映射关系”
只要发生一次 GC(无论 Minor GC 还是 Full GC),且该对象仅被弱引用持有,就会立即被回收。它的生命周期完全由 GC 触发时机决定,不依赖内存压力。
- 最常见于
WeakHashMap:key 是弱引用,value 不影响 key 的存活,避免 map 持久引用导致内存泄漏 -
ThreadLocal内部使用弱引用存储 key(即 ThreadLocal 实例本身),防止线程长期运行时 ThreadLocal 对象无法卸载 - 适合临时绑定、监听器注册等“附属关系”,主对象销毁后,附属对象应自然失效
虚引用仅用于“回收前通知”
虚引用不阻止回收,也不能通过 .get() 获取对象(始终返回 null)。它唯一作用是:当对象被 GC 回收前,JVM 会把该虚引用加入关联的 ReferenceQueue,供程序感知回收时机。
- 必须搭配
ReferenceQueue使用,否则毫无意义 - 典型用途是资源清理钩子,比如堆外内存(DirectByteBuffer)的释放、文件句柄关闭
- 不能替代
finalize()(已废弃),因为虚引用不参与对象复活,只做事后通知
不复杂但容易忽略:引用类型的选择本质是权衡“对象保留意愿”与“内存可控性”。强引用保命,软引用保缓存,弱引用保结构清洁,虚引用保资源闭环。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











