一句话总结:
Java 的四种引用就像租房合同——强引用是长租,软引用是临时住,弱引用是随时赶,虚引用是收尸队!
一、强引用(Strong Reference)——房东的亲儿子
特点:只要强引用存在,对象永不回收(哪怕内存爆炸)。
代码示例:
Object obj = new Object(); // 强引用
obj = null; // 断开引用,对象变垃圾
适用场景:
- 日常开发中的普通对象(99% 的情况都在用强引用)。
- 必须长期存活的核心对象(如数据库连接池)。
避坑:
- 内存泄漏:强引用忘记置空 → 对象无法回收 → 程序崩溃!
二、软引用(Soft Reference)——临时租客
特点:内存不足时,垃圾回收器会回收软引用对象。
代码示例:
SoftReference<byte[]> cache = new SoftReference<>(new byte[1024 * 1024]); // 1MB 缓存
byte[] data = cache.get(); // 获取对象(可能为 null)
适用场景:
- 缓存大对象(如图片缓存、临时数据),内存不够自动释放,避免 OOM。
- 敏感数据保护:内存吃紧时优先释放缓存,保住核心功能。
实战技巧:
- 配合
ReferenceQueue监听回收事件,及时清理资源。
三、弱引用(Weak Reference)——随时被赶走
特点:只要发生垃圾回收,弱引用对象立刻被回收。
代码示例:
WeakReference<Object> weakRef = new WeakReference<>(new Object());
System.out.println(weakRef.get()); // 有值
System.gc(); // 强制触发 GC(仅测试用)
System.out.println(weakRef.get()); // null(被回收)
适用场景:
- 存储临时元数据(如线程上下文信息),不用时自动清理。
- 避免内存泄漏:典型应用
WeakHashMap(键是弱引用,适合做缓存)。
实战代码:
// 使用 WeakHashMap 防止内存泄漏
WeakHashMap<Object, String> weakMap = new WeakHashMap<>();
Object key = new Object();
weakMap.put(key, "value");
key = null; // 强引用断开,GC 后 weakMap 自动清除条目
四、虚引用(Phantom Reference)——收尸队
特点:虚引用无法获取对象,唯一用途是监听对象被回收。
代码示例:
ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantomRef = new PhantomReference<>(new Object(), queue);
// 监控队列,对象被回收时收到通知
new Thread(() -> {
try {
Reference<?> ref = queue.remove();
System.out.println("对象被回收了!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
适用场景:
- 精准管理堆外内存(如 NIO 的 DirectByteBuffer,回收时需手动释放)。
- 资源清理:确保某些资源(如文件句柄)在对象回收后释放。
注意:必须配合 ReferenceQueue 使用,否则毫无意义。
四种引用对比表
| 引用类型 | 回收时机 | 常见场景 | 类比 |
|---|---|---|---|
| 强引用 | 永不回收(除非断引用) | 普通对象 | 长租合同 |
| 软引用 | 内存不足时回收 | 缓存 | 临时租客 |
| 弱引用 | GC 发生时回收 | 临时元数据、WeakHashMap | 随时赶走 |
| 虚引用 | 回收后通知 | 堆外内存管理、资源清理 | 收尸队+通知 |
避坑指南
- 软引用不是保险箱:内存足够时可能长期不回收,别用它存关键数据。
- 弱引用慎用于缓存:GC 频繁会导致缓存频繁失效,性能反而下降。
- 虚引用别滥用:多数场景用不到,除非涉及底层资源管理。
总结口诀:
“强引用不回收,软引用缓存放。
弱引用随时清,虚引用收尸用。
四种引用各司职,内存管理更轻松!”