强引用不会被GC回收,哪怕内存溢出;软引用在内存不足时才回收,适合内存敏感型缓存;弱引用在每次GC时都可能被回收,用于无泄漏映射;虚引用仅用于跟踪对象回收时间点,必须配合ReferenceQueue使用。

强引用不会被GC回收,哪怕内存溢出也不会
只要对象有强引用指向它,JVM 就认定这个对象“正在使用”,无论当前堆内存多么紧张,GC 都不会回收它。这是最常见、最“霸道”的引用类型。
典型写法:
Object obj = new Object();这里的
obj 就是强引用。只要 obj 还在作用域内(没被赋值为 null,也没超出作用域),对应对象就绝对安全。
容易踩的坑:
- 缓存场景下误用强引用,导致大量对象长期驻留堆中,引发
OutOfMemoryError: Java heap space - 忘记置
null或及时释放集合引用(比如静态Map不断put),造成内存泄漏
软引用只在内存不足时才回收,适合做内存敏感型缓存
SoftReference 的核心行为是:JVM 在抛出 OutOfMemoryError 之前,会尝试回收所有软引用指向的对象。它比强引用“松”一点,但比弱引用“倔”一点。
立即学习“Java免费学习笔记(深入)”;
实操建议:
- 用在图片缓存、JSON 解析结果缓存等「有用但非必需」的场景
- 构造时可传入
ReferenceQueue监听是否被回收:ReferenceQueue
- 获取对象必须判空:
Object obj = ref.get(); if (obj != null) { ... },因为get()可能返回null
注意:JDK 8+ 中软引用的回收策略受 -XX:SoftRefLRUPolicyMSPerMB 影响,默认每 MB 堆空间保留软引用 1000ms,不是“越晚用越优先保留”——这点常被误解。
弱引用只要GC发生就可能被回收,适合构建无内存泄漏的映射关系
WeakReference 的特点是:下一次 GC(哪怕是 Young GC)都可能把它干掉。它不阻止对象被回收,只提供一种“观察式”访问能力。
典型用途:
-
WeakHashMap的 key 是弱引用,避免 key 对象无法释放导致 value 永远不能被回收 - 监听器解注册、临时上下文绑定(如
ThreadLocal内部也依赖弱引用防止内存泄漏)
实操要点:
- 永远不要假设
WeakReference.get()一定返回非空值 - 不要用弱引用实现“延迟初始化缓存”,它太不可控;该用软引用或 Caffeine
- 弱引用对象被回收后,其关联的
ReferenceQueue会收到通知,可用于清理资源
虚引用唯一作用是跟踪对象被回收的时间点,必须配合ReferenceQueue使用
PhantomReference 是最特殊的:它的 get() 方法永远返回 null,你根本拿不到它引用的对象。它存在的唯一意义,是在对象被 GC 后,往注册的 ReferenceQueue 里塞一个通知。
真实使用场景极少,但关键:
- 替代
finalize()实现更可控、更及时的资源清理(比如直接内存ByteBuffer的清理) - JDK 自身在
DirectByteBuffer中用虚引用 +Cleaner(本质是虚引用增强版)管理堆外内存
必须注意:
- 虚引用必须与
ReferenceQueue一起使用,否则毫无意义 - 对象进入
ReferenceQueue时,已经处于“finalizable”之后、“已回收”之前的状态,此时对象内存尚未释放,但逻辑上已不可达 - 别试图在
enqueue后再通过虚引用访问对象——get()永远是null
虚引用的复杂性不在语法,而在于它把对象生命周期的控制权从 JVM 手动交还给程序员,稍有不慎就会漏掉清理或重复清理。真正要用它,往往意味着你在写框架级代码,而不是业务逻辑。










