Java四种引用的核心区别在于GC回收策略不同:强引用绝不回收,软引用内存紧张时回收,弱引用每次GC都回收,虚引用不阻止回收仅通知回收。

Java 中四种引用的核心区别在于:GC 对它们的回收策略不同,直接决定了对象的存活时间与使用目的。选哪种,关键看你要不要让对象“被回收”、什么时候回收、以及是否需要感知回收动作。
强引用:默认且最硬,不回收是底线
Object obj = new Object() 就是强引用。只要这个变量还指向对象,GC 绝对不会动它——哪怕内存快爆了,JVM 宁愿抛 OutOfMemoryError 也不会回收。它适合所有必须长期存活的业务对象,比如 Service 实例、配置类、用户会话数据等。
注意点:
- 强引用滥用是内存泄漏主因,比如缓存 Map 里长期存着大对象又不清理;
- 用完记得显式置 null(尤其在长生命周期容器中),帮助 GC 判断可达性;
- ArrayList 的 clear() 方法把每个元素设为 null,就是为释放强引用链。
软引用:内存紧张时才放手,适合缓存
SoftReference<T> softRef = new SoftReference<>(obj)。它像一个“弹性缓存开关”:内存够用就留着,OOM 前 GC 会优先清掉它。典型场景是图片缓存、HTML 页面缓存、查询结果缓存等。
立即学习“Java免费学习笔记(深入)”;
建议用法:
- 搭配 ReferenceQueue 使用,可监控哪些缓存项被回收;
- 不要依赖它“一定不被回收”,get() 返回 null 是正常情况,每次取值前必须判空;
- 它不能防止 OOM,只是延缓——如果缓存对象太大或太多,软引用照样救不了。
弱引用:GC 一来就走,防泄漏利器
WeakReference<T> weakRef = new WeakReference<>(obj)。只要发生任意一次 GC,不管内存多宽裕,对象立刻被回收。它的核心价值不是“保对象”,而是“不拦着回收”。
典型用途:
- WeakHashMap:key 是弱引用,避免 key 持有导致 value 无法释放;
- ThreadLocal 的内部实现:value 关联的 key 是弱引用,防止线程长期运行时 ThreadLocalMap 泄漏;
- 监听器注册表:避免监听器对象被持有而无法回收。
务必注意:weakRef.get() 可能随时返回 null,每次访问都得检查。
虚引用:不挡回收,只发通知
PhantomReference<T> phanRef = new PhantomReference<>(obj, queue)。它最特殊:get() 永远返回 null,完全无法访问对象本身。唯一作用是——当对象被 GC 回收前,JVM 会把它加入关联的 ReferenceQueue,让你知道“它要没了”。
适用场景有限但关键:
- 堆外内存(如 DirectByteBuffer)的资源清理;
- 敏感对象销毁前的审计日志或状态归档;
- 必须配合 ReferenceQueue 使用,单独创建虚引用毫无意义。
引用强度从高到低是:强 > 软 > 弱 > 虚。选择本质是权衡:你要的是确定性(强)、弹性(软)、无阻碍(弱),还是事后通知(虚)。实际开发中,95% 场景用强引用;缓存加一层软引用;防泄漏用弱引用;系统级资源管理才用虚引用。


















