强引用、软引用、弱引用、虚引用

Author Avatar
丁起男 12月 29,2020
  • 在其它设备中阅读本文章

强引用、软引用、弱引用、虚引用

jvm垃圾回收中,gc判断堆中的对象实例或数据是不是垃圾的方法有引用计数法可达性算法两种

无论是通过引用计数算法判断对象的引用数量,还是通过根搜索算法判断对象的引用链是否可达,判断对象是否存活都与"引用"有关

引用

jdk1.2之前,java中的引用的定义很传统:如果reference类型的数据中存储的数值代表的是另外一块内存的起始地址,就该称refrence数据是代表某块内存、某个对象的引用。这种定义很纯粹,但是太过狭隘,一个对象在这种定义下只有被引用或者没有被引用两种状态,对应如何描述一些“食之无味,弃之可惜”的对象就显得无能为力

比如我们希望能描述这样一类对象:当内存空间还足够时,则能保留在内存中;如果内存在进行垃圾收集后还是非常紧张,则可以抛弃这些对象。很多系统的缓存功能都符合这样的应用场景

jdk1.2之后,java对引用的概念进行了扩充,将引用分为

  • 强引用(strong reference)
  • 软引用(soft reference)
  • 弱引用(weak reference)
  • 虚引用(phantom reference)

这四种引用类型强度依次逐渐减弱

java中引入四种引用的目的是让程序员自己决定对象的生命周期,jvm是通过拦截回收器对这四种引用做不同的处理,来实现对象生命周期的改变

强引用

在java中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。类似Object obj = new Object()这类的引用

当一个对象被强引用引用时,它处于可达状态,是不可能被垃圾收集器回收的,即使该对象永远不会被用到也不会被回收

当内存不足,jvm开始垃圾回收,对于强引用的对象,就算出现了OOM也不会对该对象进行回收。因此强引用有时也是造成java内存泄漏的原因之一

对于一个普通的对象,如果没有其他的引用关系,只要超过了引用的作用域或者显示地将相应强引用置为null,一般认为就是可以被垃圾收集器回收

软引用

软引用是一种相对强引用弱化了一些的引用,需要用java.lang.ref.SoftReference类来实现,可以让对象豁免一些垃圾收集

软引用用来描述一些还有用,但并非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中并进行第二次回收。如果这次回收还是没有足够的内存,才会抛出内存溢出异常

对于只有软引用的对象来说:当系统内存充足时它不会被回收,当系统内存不足时它才会被回收

弱引用

弱引用也是用来描述非必须对象的,打算它的轻度比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象

弱引用需要用java.lang.ref.WeakReference类来实现,它比软引用的生存期更短

虚引用

虚引用也称为“幽灵引用”或者“幻影引用”,它是最弱的一种引用关系

虚引用,顾名思义,就是形同虚设,与其他几种引用都不太一样,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例

虚引用需要java.lang.ref.PhantomReference来实现

如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,它不能单独使用也不能通过它访问对象,虚引用必须和引用队列(RefenenceQueue)联合使用

虚引用的主要作用是跟踪对象垃圾回收的状态。仅仅是提供了一种确保对象被finalize以后,做某些事情的机制

PhantomReference的get方法总是返回null,因此无法访问对应的引用对象。其意义在于说明一个对象已经进入finalization阶段,可以被gc回收,用来实现比finalization机制更灵活的回收操作

换句话说,设置虚引用的唯一目的,就是在这个对象被回收器回收的时候收到一个系统通知或者后续添加进一步的处理

java允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作

引用队列

ReferenceQueue是用来配合引用工作的,没有ReferenceQueue一样可运行

SoftReference、WeakReference、PhantomReference都有一个可以传递ReferenceQueue的构造器

创建引用的时候,可以指定关联的队列,当gc释放对象内存的时候,会将引用加入到引用队列。如果程序发现某个虚引用已经被加入到引用队列,那么就可以在引用的对象内存被回收之前采取必要的行动,这相当于是一种通知机制

当关联的引用队列中有数据的时候,意味着指向的堆内存中的对象被回收。通过这种方式,jvm允许我们在对象销毁后,做一些我们自己想做的事情

原文:https://mp.weixin.qq.com/s/VYeB6J8zx6mR8DAQENKIBw