四种引用本质是JVM提供的对象存活控制粒度,区别在于GC处理策略:强引用永不回收、软引用内存不足时回收、弱引用每次GC必回收、虚引用仅用于回收通知且get()恒返回null。

强引用、软引用、弱引用和虚引用,本质是 JVM 给开发者提供的四种“对象存活控制粒度”,核心区别不在语法,而在 GC(垃圾回收器)对它们的处理策略不同——也就是“什么时候收、收不收、能不能用”这三件事。
强引用:默认存在,GC 绝不碰它
Object obj = new Object(); 这就是强引用。只要 obj 这个变量还有效(没被设为 null、没出作用域),JVM 宁愿抛 OutOfMemoryError 也不会回收它。它是内存泄漏的头号推手,比如静态 Map 里长期存着不用的对象,就因为强引用锁死了生命周期。
- 回收时机:永不主动回收(OOM 也不放)
- get() 是否可用:始终可用
- 典型场景:普通业务对象、单例、配置类实例
软引用:内存告急时的“缓存守门员”
SoftReference<byte[]> imgRef = new SoftReference<>(imageBytes); 软引用对象在内存充足时稳如泰山,只有 JVM 判定“再不回收就要 OOM”时,才会批量清理它们。它不是按需释放,而是由 GC 在内存压力下统一决策。
- 回收时机:仅当堆内存即将耗尽(GC 前检测到内存不足)
- get() 是否可用:回收前可取;回收后返回 null
- 典型场景:图片缓存、HTML 页面缓存等内存敏感型缓存
弱引用:GC 扫到就清,不留过夜
WeakReference<String> keyRef = new WeakReference<>(key); 只要发生一次 GC(哪怕只是 Young GC),所有仅被弱引用持有的对象都会被立刻回收。它不看内存是否紧张,只看“有没有强引用撑腰”。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
- 回收时机:下一次 GC 触发时必回收
- get() 是否可用:GC 前可用;GC 后立即为 null
- 典型场景:WeakHashMap 的 key、ThreadLocal 的 value(防内存泄漏)、临时上下文绑定
虚引用:不能取对象,只等“回收通知”
PhantomReference<MyObj> phRef = new PhantomReference<>(obj, queue); 虚引用 get() 永远返回 null,它唯一作用是——当 obj 被回收前,JVM 自动把 phRef 加入关联的 ReferenceQueue。你得靠轮询队列,才知道“某个对象刚没了”。
- 回收时机:对象进入 F-Queue 等待清除时即视为可回收
- get() 是否可用:永远返回 null(设计如此)
- 典型场景:资源清理钩子(如关闭堆外内存、释放文件句柄)、监控对象生命周期
强度排序是固定的:强 > 软 > 弱 > 虚。选哪种,关键看你要不要“让 GC 有选择权”——强引用说“绝不放手”,软/弱引用说“看情况松手”,虚引用说“我连手都不伸,只负责敲钟”。

















