Java中的四大引用类型详解

Java中的四大引用类型详解

Java中的四大引用类型详解:强引用、软引用、弱引用、虚引用

1. 引用类型概览

Java提供了四种不同强度的引用类型,用于控制对象的生命周期和垃圾回收行为:

引用类型回收时机典型应用场景是否影响GC强引用永不回收(除非断开引用)普通对象创建不回收软引用内存不足时回收缓存实现可能回收弱引用下次GC必定回收临时缓存/监听器必定回收虚引用随时可能回收(跟踪回收状态)对象回收跟踪特殊用途

2. 强引用(Strong Reference)

特点

默认引用类型:Object obj = new Object()就是强引用回收条件:只有当没有任何强引用指向对象时才会被回收

代码示例

// 强引用示例

String strongRef = new String("Strong Reference");

// 断开强引用(此时对象可被GC回收)

strongRef = null;

内存泄漏场景

List leakList = new ArrayList<>();

while(true) {

leakList.add(new Object()); // 不断添加对象且不释放

}

// 即使不再使用,由于List持有强引用,对象无法被回收

3. 软引用(Soft Reference)

特点

内存敏感缓存:当内存不足时才会被回收比弱引用"强":JVM会尽量保留软引用对象

代码示例

// 创建软引用

SoftReference softRef =

new SoftReference<>(new byte[1024 * 1024]); // 1MB

// 获取引用对象(可能返回null)

byte[] data = softRef.get();

if(data == null) {

// 对象已被回收,需要重新创建

data = new byte[1024 * 1024];

softRef = new SoftReference<>(data);

}

典型应用

图片缓存(Android的LruCache内部使用)计算结果缓存(当内存紧张时自动释放)

4. 弱引用(Weak Reference)

特点

短期缓存:只要发生GC就会被回收不会阻止回收:比软引用更脆弱

代码示例

// 创建弱引用

WeakReference weakRef =

new WeakReference<>(new Object());

// 手动触发GC(仅用于演示)

System.gc();

// 大概率返回null

System.out.println(weakRef.get());

典型应用

// 1. WeakHashMap键的自动清理

WeakHashMap map = new WeakHashMap<>();

map.put(new Object(), "value"); // 键对象无其他强引用时会被自动移除

// 2. 监听器防内存泄漏

public class MyListener {

void register() {

someService.register(new WeakReference<>(this));

}

}

5. 虚引用(Phantom Reference)

特点

最弱引用:无法通过get()获取对象回收跟踪:用于监控对象被回收的时机

代码示例

// 创建引用队列

ReferenceQueue queue = new ReferenceQueue<>();

// 创建虚引用(必须关联队列)

PhantomReference phantomRef =

new PhantomReference<>(new Object(), queue);

// 永远返回null(与其他引用不同)

System.out.println(phantomRef.get()); // null

// 监控回收(通常另启线程检查队列)

new Thread(() -> {

try {

Reference ref = queue.remove();

System.out.println("对象被回收了:" + ref);

} catch (InterruptedException e) {

Thread.currentThread().interrupt();

}

}).start();

典型应用

NIO的DirectByteBuffer清理(通过Cleaner机制)资源精确释放(如知道某大对象何时被回收后执行清理)

6. 引用队列(ReferenceQueue)

所有引用类型都可以关联引用队列,用于跟踪引用对象的状态变化:

ReferenceQueue queue = new ReferenceQueue<>();

// 创建带队列的弱引用

WeakReference ref =

new WeakReference<>(new Object(), queue);

System.gc();

// 检查队列(非阻塞)

Reference polledRef = queue.poll();

if(polledRef != null) {

System.out.println("对象已被回收");

}

7. 四种引用的GC行为对比

引用类型get()行为是否入队列典型GC时机强引用返回对象不适用永不回收软引用可能返回null内存不足时入队内存不足时弱引用可能返回nullGC后入队下次GC虚引用永远返回nullGC后入队不确定(最优先回收)

8. 实战建议

缓存选择:

需要长期缓存 → 软引用临时缓存 → 弱引用

内存泄漏排查:

// 检查弱引用是否异常存活

WeakReference ref = new WeakReference<>(suspectObj);

System.gc();

if(ref.get() != null) {

System.out.println("存在强引用持有!");

}

相关文章