强引用
强引用是无论在任何情况下,只要强引用关系还存在,即使垃圾收集器进行垃圾回收,甚至抛出OOM,也不会回收掉被引用的对象,如下代码片段:
Object obj = new Object();
软引用
软引用是用来描述一些还有用,但非必须的对象。只被软引用关联着的对象,若JVM内存足够时,即使触发垃圾回收也不会回收该对象;但当JVM内存不够时,系统在发生OOM之前,就会对这些对象进行回收,若回收之后,还是没有足够的空间时,才会抛出OOM。下面我们用示例代码来说明:
/**
* 软引用
* <p>
* -Xmx10M -Xms10M -XX:+PrintGCDetails
*/
public class SoftTest {
public static void main(String[] args) throws Exception {
SoftReference<Soft> soft = new SoftReference<>(new Soft());
System.out.println("手动触发gc前:" + soft.get());
// 手动触发一次gc
System.gc();
// 睡眠1秒钟,等待手动触发gc能够成功
TimeUnit.SECONDS.sleep(1);
System.out.println("手动触发gc后:" + soft.get());
// 再尝试创建一个强引用对象,分配5M内存
// 因为我们堆空间最大10M内存,会出现Full GC
Soft soft1 = new Soft();
System.out.println("jvm内存不足后:" + soft.get());
}
}
class Soft {
// 申请一个5M内存的数组
private byte[] filed = new byte[1024 * 1024 * 5];
}
运行上面的代码,并设置运行时参数:-Xmx10M -Xms10M -XX:+PrintGCDetails,运行结果如下图所示:
从运行结果来看,在jvm内存足够时,即使手动触发一次GC,被软引用的对象没有被回收,但是一旦内存不足触发GC后,只被软引用着的对象会被回收。
弱引用
弱引用也是用来描述那些非必须的对象,它比软引用的强度更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集器发生为止,即只要垃圾收集器开始工作,无论jvm内存是否充足,都会回收掉只被弱引用关联的对象。下面我们用如下代码示例说明:
/**
* 弱引用
* <p>
* -XX:+PrintGCDetails
*/
public class WeakTest {
public static void main(String[] args) throws Exception {
WeakReference<Weak> weak = new WeakReference<>(new Weak());
System.out.println("手动触发gc前:" + weak.get());
// 手动触发一次gc
System.gc();
// 睡眠1秒钟,等待手动触发gc能够成功
TimeUnit.SECONDS.sleep(1);
System.out.println("手动触发gc后:" + weak.get());
}
}
class Weak {
}
运行上面的代码,并设置运行时参数:-XX:+PrintGCDetails,运行结果如下图所示:
虚引用
虚引用是一种最弱的引用关系,一个对象是否存在虚引用,完全不会对其生存时间构成任何影响,也无法通过虚引用来取得一个对象的实例。为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知,我们可以查看JDK定义的PhantomReference类,从类中可以看到,创建虚引用时,必须与一个引用队列进行关联,代码如下:
总结
最后做一个总结:
强引用:JVM即使内存不足时,抛出OOM,也不会回收掉强引用关联的对象;
软引用:JVM即使内存不足时,才会回收掉软引用关联的对象;
弱引用:垃圾收集器工作时,无论内存是否足够,都会回收掉弱引用关联的对象;
虚引用:不会影响虚引用关联对象的生存时间。