强引用是new创建且被变量直接持有的引用,JVM绝不回收;弱引用需WeakReference包装,无强/软引用时GC即回收;软引用在内存不足时才回收,适合图片缓存;引用队列用于监听回收事件。

强引用就是 new 出来的普通对象引用
只要一个对象被 new 出来,且至少有一个变量直接持有它,这个引用就是强引用。JVM 不会在任何 GC 阶段回收它,哪怕内存溢出(OutOfMemoryError)也不会动它。
常见错误现象:缓存用 HashMap 存大量对象,key 或 value 全是强引用 → 内存一直涨,GC 无效 → OOM。
-
String str = new String("hello");——str是强引用 - 局部变量、成员变量、静态变量默认持有的都是强引用
- 强引用对象生命周期完全由代码显式控制(比如赋值为
null、离开作用域)
弱引用必须用 WeakReference 显式包装
弱引用不会阻止 GC 回收所指向的对象。只要该对象没有其他强/软引用,下一次 GC 就可能被清除。典型用途是实现“用完即弃”的缓存,比如 WeakHashMap 的 key 就是弱引用。
注意:WeakReference.get() 返回的是 Object,需要手动转型;而且随时可能返回 null,不判空直接用会抛 NullPointerException。
立即学习“Java免费学习笔记(深入)”;
- 不能直接写
String weakStr = ...声明弱引用 —— 语法上就不支持 - 必须写:
WeakReference
wr = new WeakReference<>(new String("hello")); - 使用前务必检查:
if (wr.get() != null) { System.out.println(wr.get()); }
软引用和弱引用的关键区别在 GC 触发时机
软引用(SoftReference)比弱引用“撑得久一点”:只有 JVM 判定内存不足时(比如 Eden 区 + Survivor 区都满了,准备触发 Full GC),才会尝试回收软引用对象;而弱引用在每次 GC(包括 Young GC)时都会被清掉。
所以软引用适合做内存敏感型缓存(如图片缓存),弱引用更适合做生命周期依附于外部对象的映射(如监听器注册表)。
- 软引用示例:
SoftReference
sr = new SoftReference<>(new byte[1024 * 1024]); - 弱引用回收更激进,适合临时关联、非关键数据;软引用回收更保守,适合“尽量留着但可丢”的场景
- 两者都不能防止对象被回收,只是回收策略不同 —— 别指望靠它们“保命”
引用队列(ReferenceQueue)是用来监听回收事件的
单独用 WeakReference 或 SoftReference,你没法知道对象啥时候被回收了。加个 ReferenceQueue,就能在对象被 GC 后立刻收到通知,用于清理关联资源(比如关闭文件句柄、注销监听器)。
容易踩的坑:队列里拿到的是引用对象本身(如 WeakReference 实例),不是原始对象;而且必须主动调用 queue.poll() 或 queue.remove() 取出,否则队列会越积越多。
- 绑定队列写法:
ReferenceQueue
queue = new ReferenceQueue<>(); WeakReference wr = new WeakReference<>(str, queue); - 监听回收:
Reference extends String> ref = queue.poll(); if (ref != null) { /* 对象已回收,执行清理 */ } - 别忘了:引用对象本身(
wr)还在堆里,直到它自己也被 GC —— 它只是个轻量级壳子
弱引用和软引用真正起效的前提,是目标对象不再有强引用链可达。很多开发者以为“包一层就变弱”,结果对象还被某个集合、监听器、静态 Map 悄悄持有着,那再弱也没用。查泄漏时,先看 GC Roots 路径,而不是只盯引用类型声明。










