引用类型及WeakReference应用

204 阅读4分钟

juejin.cn/post/684490…

引用类型包括强引用、软引用、弱引用、虚引用。不同的引用类型具有各自适用的应用场景,并与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. 虚引用

无论是SoftReferenceWeakReference还是PhantomReference,作为Reference类的子类,自身更多只是作为引用类型的对象,去标记用的,类中没有过多的自身的逻辑。与引用类型的逻辑处理过程,绝大部分都是在虚拟机中实现的。

有一大不同的是,PhantomReference类中,重写了T get()方法,直接返回了null

就是说,通过虚引用对象get()方法,是无法获取到目标对象实体的。但实际上,虚引用对象中的referent还是指向目标对象实体的。也正因为如此,使用到虚引用对象时,往往都需要传一个引用队列,否则,构建的虚引用就没有任何意义了。

同样,虚拟机在GC时,目标对象实体被GC后,会被入队到引用队列中。

WeakReference特性总结

相比SoftReferencePhantomReferenceWeakReference应用更加普遍。主要得益于WeakReference提供的特性:
1,提供了一种监测目标对象实体是否已经被垃圾回收的方法;
2,同时不改变目标对象实体本身的生命周期;
3,对外提供了T get()方法去尝试获取到目标对象。