对象引用类型

强引用

被强引用关联的对象不会被回收。

1
Object obj = new Object();

软引用

被软引用关联的对象只有在内存不够的情况下才会被回收。
作用: 缓存

1
2
3
Object obj = new Object();
SoftReference<Object> sf = new SoftReference<Object>(obj);
obj = null; // 使对象只被软引用关联

// ===== 软引用测试(-Xms:20M -Xmx20M) =====

SoftReference<byte[]> m = new SoftReference<>(new byte[1024102410]);
System.out.println(m.get());

// 再分配一个数组,heap 将装不下,这时候系统会垃圾回收,先回收一次,如果不够,会把软引用干掉
byte[] b = new byte[1024102415];
System.out.println(m.get()); // null

弱引用

被弱引用关联的对象一定会被回收,也就是说它只能存活到下一次垃圾回收发生之前。

作用: 一般用在容器里。强引用和弱引用同时指向某个对象,当强引用不再指向该对象时,该对象就该被回收

例:ThreadLocal 对象 new 后有强引用,而当前线程中的 ThreadLocalMap 对象的键也有 ThreadLocal 对象的弱引用,所以当 ThreadLocal 对象失去强引用时 ThreadLocalMap 中对应的键也会变为 null,防止了内存泄露。虽然 ThreadLocalMap 的键为 null 了,但是其 value 值还存在所以依然会有内存泄露,所以需要执行 ThreadLocal#remove 方法

1
2
3
Object obj = new Object();
WeakReference<Object> wf = new WeakReference<Object>(obj);
obj = null;

WeakReference m = new WeakReference<>(new M());

System.out.println(m.get());
System.gc();
System.out.println(m.get()); // null

ThreadLocal tl = new ThreadLocal<>();
tl.set(new M());
tl.remove();

虚引用

又称为幽灵引用或者幻影引用。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用取得一个对象。

作用:

  • 为一个对象设置虚引用关联的唯一目的就是能在这个对象被回收时收到一个系统通知。
  • 管理堆外内存(通常给编写 JVM 的人使用):DirectByteBuffer 对象指向堆外内存。当 DirectByteBuffer 被回收时,可以通过队列检测到,然后清理堆外内存
1
2
3
4
5
6
7
8
9
10
11
12
// 关联了对象和队列
// 当对象被回收引用会放入队列中
ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> pf = new PhantomReference<Object>(new Object(), queue);
// 不能通过 get() 拿到里面的值
pf.get();
...
// 对象被回收后,通过 poll() 方法可以拿出
Reference<? extends Object> poll = queue.poll();
if (poll != null) {
System.out.println("--- 虚引用对象被jvm回收了 ---- " + poll);
}