Skip to content

四种引用(强、软、弱、虚)

一、强引用

1. 定义与回收规则

普通对象赋值即为强引用,只要GC Roots存在强引用链指向该对象,永远不会被回收;只有切断所有强引用,对象才会判定为垃圾。

java
User user = new User();

2. 特点与场景

日常代码默认使用,容易造成内存泄漏(静态集合持有对象长期不释放)。

二、软引用 SoftReference

1. 回收规则

仅存在软引用指向对象时:

  1. 普通GC不会回收;
  2. 堆内存不足、即将发生OOM时,会主动回收所有软引用对象释放内存。
java
User user = new User();
SoftReference<User> softRef = new SoftReference<>(user);
user = null;

2. 使用场景

缓存框架,内存充足时缓存复用,内存紧张自动清理缓存。

三、弱引用 WeakReference

1. 回收规则

仅存在弱引用指向对象时,只要发生GC,无论内存是否充足,都会直接回收

java
User user = new User();
WeakReference<User> weakRef = new WeakReference<>(user);
user = null;

2. 延伸:ThreadLocal内存泄漏

ThreadLocal底层Entry继承WeakReference<ThreadLocal<?>>

  • key是弱引用,线程GC时ThreadLocal实例会被回收;
  • value是强引用,若线程长期存活(线程池),value无法释放,造成内存泄漏; 解决:使用完调用remove()清除value。

四、虚引用 PhantomReference

1. 基础规则

  1. 必须搭配ReferenceQueue引用队列使用;
  2. 无法通过get()获取原对象,仅用于跟踪对象回收时机;
  3. 对象被回收后,虚引用实例会被放入队列,由Reference Handler后台线程处理资源释放。
java
User user = new User();
ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<User> phantomRef = new PhantomReference<>(user, queue);
user = null;

2. 使用场景

管理堆外直接内存,对象回收时通过队列回调释放Native内存,避免堆外内存泄漏。

五、四种引用总结

  1. 强引用:GC Roots可达则永不回收,常规对象使用;
  2. 软引用:内存充足保留,内存不足OOM前回收,做缓存;
  3. 弱引用:只要GC就回收,ThreadLocal、临时缓存;
  4. 虚引用:仅跟踪回收时机,配合队列释放堆外资源。

六、面试简答

问:强引用、软引用、弱引用、虚引用的区别?

答:

  1. 强引用:普通赋值引用,只要GC Roots可达,不会被回收;
  2. 软引用SoftReference:内存充足时存活,堆内存不够即将OOM时回收,适合缓存;
  3. 弱引用WeakReference:每次GC都会回收,ThreadLocal底层使用弱引用key,不手动remove会出现value内存泄漏;
  4. 虚引用PhantomReference:必须绑定引用队列,无法获取对象,仅在对象回收后入队,用来释放堆外直接内存。

Powered by VitePress 1.6.4 | 持续更新中