强引用
强引用是Java中最常见的引用,如Object o = new Object()
中,新建的o
对象就是一个强引用。如果一个对象被强引用,当JVM内存不足时,GC也绝对不会回收强引用对象,就可能会导致内存溢出,从而抛出OutOfMemoryError
异常。
软引用
软引用的强度弱于强引用,由SoftReference
来表示。当JVM内存不足时,GC会回收那些被软引用的对象,避免内存溢出。在GC释放软引用对象后,如果JVM内存仍然不足,才会抛出OutOfMemoryError
异常。
软引用适合那些可以通过其他方式恢复的对象,例如,数据库缓存中的对象就可以通过数据库恢复,所以软引用可以用来实现缓存。另外,由于程序在使用软引用之前的某个时刻,其所指向的对象可能已经被GC所回收,所以通过SoftReference.get()
方法来获取软引用所指向的对象时,总是要通过检查该方法的返回值是否为null,来判断被软引用的对象是否存活。
弱引用
弱引用的强度弱于软引用, 由WeakReference
类来表示。弱引用的使用方法和软引用类似。如果指向一个对象的引用都是弱引用,发生GC时,GC都会回收该对象。由此可知,弱引用对象的生命周期是两次GC之间的这段时间,而只被软引用的对象可以经历多次GC,直到出现内存紧张时才会被回收。
虚引用
虚引用的强度小于弱引用,由PhantomReference
类来表示。PhantomReference.get()
方法始终返回null。
引用队列
通常,我们需要在一个对象的可达性发生变化时(是否可以被GC回收)得到通知,引用队列就是用来收集这些信息的队列。在创建SoftReference
对象时,可以为其关联一个引用队列,当SoftReference
所引用的对象被GC回收时,Java虚拟机就会将该SoftReference
对象添加到与之关联的引用队列中。当需要检测这些通知信息时,就可以从引用队列中获取这些Reference
对象。不仅是SoftReference
对象,上面介绍的WeakReference和PhantomReference
对象都可以关联相应的引用队列。
总结
在以上四种引用中,不同引用类型决定了其引用对象的GC回收时机和生命周期。强引用的生命周期最长,即使JVM内存不足也不会回收。软引用对象次之,当内存不足时,GC回收软引用对象。每次GC时,JVM都会回收弱引用和虚引用对象,他们的生命周期介于两次GC之间。