作用
以代码的方法控制对象的生命周期。
以下四种引用类型对象生命周期由长至短。
强引用
new的方式默认就是强引用。
只要强引用存在,即使OOM,也不会被gc回收。
只有当显式置为null,切断了引用与对象的联系,才会被回收。所以经常会在一些地方看到 xxx = null
的写法,就是提醒jvm该对象已经不需要了,可以进行回收。
软引用
gc后如果内存空间还不够用,便会回收只有软引用指向的对象。
注意:并不是gc了就一定会回收软引用指向的对象,而是gc以后,如果内存空间还不够用才会回收,有一个缓冲期
用法:
1
2
3
4
5
6
7
8
9
10
11
// -Xms5m -Xmx5m 指定堆空间只有5M
SoftReference<Object> softReference = new SoftReference<>(new Object());
System.out.println(softReference.get()); // java.lang.Object@3b81a1bc
System.gc(); // 手动触发一次gc
System.out.println(softReference.get()); //java.lang.Object@3b81a1bc,可以看到没有被回收
try {
byte[] bytes = new byte[5 * 1024 * 1024]; // 申请一个5M的字节数组,达到最大堆空间,会触发gc
} finally {
System.out.println(softReference.get());// null,被回收了
}
使用场景:经常被用在内存敏感的场景,比如缓存。内存够用,就用缓存加速。内存不够用了,清除缓存保证程序正常运行。
弱引用
只要gc,就会回收只有弱引用指向的对象。
示例:
1
2
3
4
WeakReference<Object> softReference = new WeakReference<>(new Object());
System.out.println(softReference.get());// java.lang.Object@3b81a1bc
System.gc();
System.out.println(softReference.get());// null,被回收了
使用场景:ThreadLocal、WeakHashMap
虚引用
意义:提供一个钩子,在对象被回收后会被放入一个队列,便可以执行一些后续的自定义操作。
其实 SoftReference、WeakReference
同样提供了一个队列,提供了同样的功能,区别在于 phantomReference.get()
永远是 null
。也就是它的关注点不在于对象本身,而仅仅在于对象被回收后的自定义操作。
注意:虚引用并不是gc了就会被回收,当堆内存不够时才会被回收,如上所述,它的关注点不在于对象或者对象生命周期本身,而是对象被回收后的自定义操作。
示例:
1
2
3
4
5
6
7
8
9
10
11
12
// -Xms5m -Xmx5m 指定堆空间只有5M
ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantomReference = new PhantomReference<>(new Object(), queue);
System.out.println(phantomReference.get()); // null
System.out.println(queue.poll());// null
try {
byte[] bytes = new byte[5 * 1024 * 1024];
} finally {
System.out.println(phantomReference.get());// null
System.out.println(queue.poll());// java.lang.ref.PhantomReference@5f2050f6
}
使用场景:NIO的堆外内存管理就用到了虚引用(没有深入研究过)