在Java中引用类型分别有强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)这4 种类型,对应的引用强度依次减弱。
强引用
对于直接引用通过new关键字生成的对象就是强引用关系,此类引用必须由垃圾收集器判断确定没有任何引用关系后才能被回收。
软引用
软引用是用来处理一些有用但是并非必需的对象,这些对象就可以用软引用关联,软引用关联的对象会在系统将要发生内存溢出OOM之前回收。
下面这段代码演示了在内存不足时,将要发生OOM,所以软引用对象被回收。
-Xms10m -Xmx10m,设置最大内存10M。
public class Test {
public static void main(String[] args) {
byte[] b = new byte[1024 * 1024 * 5];
SoftReference softReference = new SoftReference(b);
b = null;
System.gc();
System.out.println("b对象没有任何引用,手动调用gc,b对象被回收:" + b + " ,软引用对象:" + softReference.get());
//由于已经存在5M对象,再分配6M肯定不够分配,所以为了避免OOM,软引用对象被回收。
byte[] b1 = new byte[1024 * 1024 * 6];
System.out.println("b1对象,超过内存最大值,触发垃圾回收,b1对象:" + b1 + " ,软引用对象被回收:" + softReference.get());
}
}
弱引用
弱引用和软件引用作用相似,只不过弱引用级别更低,在下一次垃圾回收时就会被回收,无论当前内存是否足够。
public class Test {
public static void main(String[] args) {
byte[] b = new byte[1024 * 1024 * 1];
WeakReference weakReference = new WeakReference(b);
b = null;
System.out.println("弱引用对象在gc前:" + weakReference.get());
System.gc();
System.out.println("弱引用对象在gc后:" + weakReference.get());
}
}
虚引用
对引用对象完全没有影响,随时可能被回收,唯一目的是对象在回收时能收到一个通知。
使用场景
软引用:一般都可以作为缓存使用,当做一种淘汰策略,可避免OOM。
弱引用:也可作为缓存使用,但是会更快的被清除,所以与软引用的缓存级别不相同,更适用于一些临时、短期缓存。
另外还可参考ThreadLocal中的一种使用场景,就是自动删除,避免由于key的内存泄露,key有一个强引用和一个弱引用,一旦强引用没了,就希望key能够自动回收,而不需要主要删除这个key,因为删除这个key可能比较麻烦,所以就可以通过弱引用实现。
ThreadLocal存储结构及内存溢出问题分析,这篇文章中详细说明了为什么要使用弱引用。
虚引用:java直接内存就使用了虚引用的方式,堆中有一个对象,保存了堆外内存的引用,当这个对象被回收时,会收到通知,则回收堆外内存。