引用类型包括强引用、软引用、弱引用、虚引用。不同的引用类型具有各自适用的应用场景,并与JVM的GC直接相关。
1. 强引用与GC可达
默认情况下,我们直接指向对象的引用类型为强引用;
强引用只是单纯的概念层次上的,引用变量定义时对应的类型即为实际指向对象的类型或其父类型
GC时,通过可达性去分析,如果没有强引用指向对象实体,或者即使有强引用指向,但强引用的所处的对象自身,已经不能从GC Roots可达了,这时GC,此对象实体会被垃圾回收。对象实体存在强应用可达,就不会被垃圾回收,直至发生OOM,进程终止。
2. Reference 与 ReferenceQueue
Java源码中的java.lang.ref
包,对应的是引用类型和引用队列的类定义。
Reference
类本身,是一个抽象类,作为具体引用类型的基类,定义了基本的类属性与行为,在运行时是会与虚拟机中的垃圾收集器紧密协作的
引用对象
。由具体的引用类型类(如WeakReference、SoftReference、PhantomReference)所创建出来的对象。引用对象
在创建时,外部会将目标对象实体
传入进来,从而使得引用对象
中的referent
属性去指向目标对象实体
。
引用队列
。引用对象
创建时,由外部传入ReferenceQueue
类型的对象,引用队列
中存储的是引用对象
,并且,是会在特定情况下由虚拟机将引用对象
入队。存在于引用队列
中的引用对象
,表明此引用对象
中referent
属性所指向的目标对象实体
已经被垃圾回收。
3. 软引用
首先要说明一下,一般意义上的软引用
、弱引用
和虚引用
,实际上指的都是引用对象
中的指向目标对象实体
的referent
属性。而非指此引用对象
本身。因为此referent
属性才是真正指向的目标对象实体
,且存在于具体的引用对象
中,具有具体的引用类型的特性。当然,这个特性更多是虚拟机赋予的。
特性:当目标对象实体
没有强引用可达,但有软引用指向时,在内存不够用时,才会回收目标对象实体
。
内存够用(是否够用由虚拟机判断),即使目标对象实体
只是软引用可达的,目标对象实体
也不会被GC,会一直存活。
内存足够,通过引用对象
的get()
方法,都可以获取到对象实体。
内存不够,虚拟机在GC流程中,会将引用对象
的referent
强制置为null
,此时对象实体孤立,可以被垃圾回收。
SoftReference
不一定被经常用到,虽然SoftReference
可以适当应用到如缓存等场景,但一般更通用的建议是使用如LruCache
等缓存方案。
4.弱引用
当目标对象实体
没有强引用可达,但有弱引用可达,此时,在发生GC之前,此目标对象实体
都是存活的,一旦发生GC,GC过程中会将弱引用对象
中的referent
属性置为null
,并直接将此目标对象实体
进行回收,并将此引用对象
入队到引用队列
中。
弱引用本质上,是不改变目标对象实体
的生命周期的,也不影响目标对象实体
被GC的时机,并且,还提供了一种机制,即基于引用队列
下的,去监测目标对象实体
是否已经被GC。
5. 虚引用
无论是SoftReference
、WeakReference
还是PhantomReference
,作为Reference
类的子类,自身更多只是作为引用类型的对象,去标记用的,类中没有过多的自身的逻辑。与引用类型的逻辑处理过程,绝大部分都是在虚拟机中实现的。
有一大不同的是,PhantomReference
类中,重写了T get()
方法,直接返回了null
就是说,通过虚引用对象
的get()
方法,是无法获取到目标对象实体
的。但实际上,虚引用对象
中的referent
还是指向目标对象实体
的。也正因为如此,使用到虚引用对象
时,往往都需要传一个引用队列
,否则,构建的虚引用就没有任何意义了。
同样,虚拟机在GC时,目标对象实体
被GC后,会被入队到引用队列
中。
WeakReference特性总结
相比SoftReference
和PhantomReference
,WeakReference
应用更加普遍。主要得益于WeakReference
提供的特性:
1,提供了一种监测目标对象实体
是否已经被垃圾回收的方法;
2,同时不改变目标对象实体
本身的生命周期;
3,对外提供了T get()
方法去尝试获取到目标对象。