Java四大引用类型

从Java12版本开始,对象的引用细分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)四种级别

GC回收的优先级上: 强引用->软引用->弱引用->虚引用。

#yyds干货盘点#Java四大引用类型_弱引用

强引用类型(Strong Reference)

Student student = new Student();

在代码中普遍使用,如果一个对象具有强引用,则无论在什么情况下,GC都不会回收被引用的对象。当内存空间不足时,Java虚拟机宁可抛出OutOfMemoryError终止应用程序也不会回收具有强引用的对象。

强引用是我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表明对象还“活着”,垃圾收集器不会碰这种对象。在Java中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到JVM也不会回收。因此强引用是造成Java内存泄漏的主要原因之一。
对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显式地将相应(强)引用赋值为 null一般认为就是可以被垃圾收集的了(当然具体回收时机还是要看垃圾收集策略)。

软引用(Soft Reference)

表示一个对象处在有用但非必须的状态。如果一个对象具有软引用,在内存空间充足时,GC就不会回收该对象;当内存空间不足时,GC会回收该对象的内存(回收发生在OutOfMemoryError之前)。看下面的代码所示,我们声明软引用的方法是new一个SoftReference对象,这个SoftReference是官方提供的,我们直接使用

Student student = new Student();
SoftReference st = new SoftReference(student);

我们也可以在new SoftReference对象的时候传入一个ReferenceQueue,软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被GC回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中,我们就可以通过查看这个ReferenceQueue里存储的信息来知道哪些软引用对象被回收。

软引用通常用在对内存敏感的程序中,比如高速缓存就有用到软引用,内存够用的时候就保留,不够用就回收! 这一点可以很好地用来解决OOM的问题,并且这个特性很适合用来实现缓存:比如网页缓存、图片缓存等。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被JVM回收,这个软引用就会被加入到与之关联的引用队列中。

弱引用(Weak Reference)

用来描述非必须的对象。它类似软引用,但是强度比软引用更弱一些:弱引用具有更短的生命。GC在扫描的过程中,一旦发现只具有被弱引用关联的对象,都会回收掉被弱引用关联的对象,换言之,无论当前内存是否紧缺,GC都将回收被弱引用关联的对象。(只要发生GC,则回收弱引用对象)

Student student = new Student();
WeakReference wr = new WeakReference(student);

同样的,我们也可以在new WeakReference对象的时候传入一个ReferenceQueue , 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被GC回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中,我们就可以通过查看这个ReferenceQueue里存储的信息来知道哪些弱引用对象被回收了

对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管JVM的内存空间是否足够,都会回收该对象占用的内存。
应用场景:如果一个对象是偶尔的使用,并且希望在使用时随时就能获取到,但又不想影响此对象的垃圾收集,那么应该用 Weak Reference 来记住此对象。或者想引用一个对象,但是这个对象有自己的生命周期,你不想介入这个对象的生命周期,这时候就应该用弱引用,这个引用不会在对象的垃圾回收判断中产生任何附加的影响。

虚引用(Phantom Reference)

虚引用等同于没有引用,这意味着在任何时候都可能被GC回收,设置虚引用的目的是为了被虚引用关联的对象在被垃圾回收器回收时,能够收到一个系统通知。(被用来跟踪对象被GC回收的活动)虚引用和弱引用的区别在于:虚引用在使用时必须和引用队列(ReferenceQueue)联合使用,其在GC回收期间的活动如下

ReferenceQueue queue = new ReferenceQueue();
PhantomReference pr = new PhantomReference(queue);

也即是GC在回收一个对象时,如果发现该对象具有虚引用,那么在回收之前会首先该对象的虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入虚引用来了解被引用的对象是否被GC回收。

设置虚引用关联的唯一目的,就是在这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步的处理。Java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。

总结

引用类型

被回收事件

用途

生存事件

强引用

从来不会

对象的一般状态

JVM停止运行时

软引用

内存不足时

对象缓存

内存不足时

弱引用

JVM垃圾回收时

对象缓存

GC运行后

虚引用

未知

未知

未知

在实际程序设计中一般很少使用弱引用与虚引用,使用软引用的情况较多,这是因为软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生。

利用软引用和弱引用解决OOM问题:加入有一个应用需要读取大量的本地图片,如果每次读取图片都从硬盘读取,则会严重影响性能,但是如果全部加载到内存当中,又有可能造成内存溢出,此时使用软引用可以解决这个问题。

设计思路:

设计思路是:用一个HashMap来保存图片的路径和相应图片对象关联的软引用之间的映射关系,在内存不足时,JVM会自动回收这些缓存图片对象所占用的空间,从而有效地避免了OOM的问题。