在JDK1.2中,Java对引用概念的进行了拓充,在1.2之后Java提供了四个级别的引用,按照引用强度依次排序为强引用(StrongReference
)、软引用(SoftReference
)、弱引用(WeakReference
)、虚引用(PhantomReference
)引用。除开强引用类型外,其余三种引用类型均可在java.lang.ref
包中找到对应的类,开发过程中允许直接使用这些引用类型操作。
强引用类型是Java程序运行过程中最常见的引用类型,通过new
指令创建出来的对象都属于强引用类型,堆中的对象与栈中的变量保持着直接引用。如下:
Object obj = new Object();
在上述代码中,通过new
指令创建的Object
实例会被分配在堆中存储,而变量obj
会被放在当前方法对应的栈帧内的局部变量表中存储,在运行时可以直接通过obj
变量操作堆中的实例对象,那么obj
就是该Object
实例对象的强引用。
众所周知,如果在Java程序运行过程中堆内存不足时,GC机制会被触发,GC收集器会开始检测可回收的"垃圾"对象,但是当GC器遇到存在强引用的对象时,GC机制不会强制回收它,因为存在强引用的对象都会被判定为“存活”对象,当GC扫描几圈下来之后,发现堆中的对象都存在强引用时,这种情况GC机制宁愿抛出OOM也不会强制回收一部分对象。
因为保持强引用的对象是不会被GC机制回收的,所以一般在编码时如果确定一个对象不再使用后,可以显示的将对象引用清空,如:obj=null;
,这样能够方便GC机制在查找垃圾时直接发现并标记该对象。
软引用是指使用java.lang.ref.SoftReference
类型修饰的对象,当一个对象只存在软引用时,在堆内存不足的情况下,该引用级别的对象将被GC机制回收。不过当堆内存还充足的情况下,该引用级别的对象是不会被回收的,所以平时如果需要实现JVM级别的简单缓存,那么可以使用该级别的引用类型实现。使用案例如下:
SoftReference cacheSoftRef = new SoftReference(new HashMap
如上案例中便通过软引用类型实现了一个简单的缓存器。
弱引用类型是指使用java.lang.ref.WeakReference
类型修饰的对象,与软引用的区别在于:弱引用类型的对象生命周期更短,因为弱引用类型的对象只要被GC发现,不管当前的堆内存资源是否紧张,都会被GC机制回收。不过因为GC线程的优先级比用户线程更低,所以一般不会立马发现弱引用类型对象,因此一般弱引用类型的对象也会有一段不短的存活周期。
从软引和弱引的特性上来看,它们都适合用来实现简单的缓存机制,用于保存那些可有可无的缓存数据,内存充足时可以稍微增加程序的执行效率,而内存紧张时会被回收,不会因此导致OOM。
虚引用也在有些地方被称为幽灵引用,虚引用是指使用java.lang.ref.PhantomReference
类型修饰的对象,不过在使用虚引用的时候是需要配合ReferenceQueue
引用队列才能联合使用。与其他的几种引用类型不同的是:虚引用不会决定GC机制对一个对象的回收权,如果一个对象仅仅存在虚引用,那么GC机制将会把他当成一个没有任何引用类型的对象,随时随刻可以回收它。不过它还有个额外的用途:跟踪垃圾回收过程,也正是由于虚引用可以跟踪对象的回收时间,所以也可以将一些资源释放操作放置在虚引用中执行和记录。
当GC机制准备回收一个对象时发现它还存在虚引用,那么GC机制就会在回收前,把虚引用加入到与之关联的引用队列中,程序可以通过判断队列中是否加入该虚引用,来判断被引用的对象是否将要GC回收,从而可以在finalize方法中采取一些对应的处理措施。