注意,以下所述源码版本为 JDK 1.8.0_212 

 

Java中的数据类型分为:

基本数据类型:byte、short、int、long、float、double 8种。

引用类型:上述基本数据类型的包装类、其他各种对象类型。如Integer、Object等。

当说到“引用”时,指的可能是 引用类型 或 一个引用类型的变量,具体视上下文而定。

 

在JDK1.2之前,Java中的引用的定义是十分传统的:如果reference类型的数据中存储的数值代表的是另一块内存的起始地址,就称这块内存代表着一个引用。在这种定义之下,一个对象只有被引用和没有被引用两种状态,用户代码中无法在对象被GC回收后做一些额外的工作(如清理堆外内存等)。

实际上,我们更希望存在这样的一类对象:当内存空间还足够的时候,这些对象能够保留在内存空间中;如果当内存空间在进行了垃圾收集之后还是非常紧张,则可以抛弃这些对象。基于这种特性,可以满足很多系统的缓存功能的使用场景。

从JDK 1.2起,对引用概念进行了扩充,将引用分为 强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom Reference)、终引用(Final Reference)。其中强引用就是JDK 1.2之前的引用,日常代码中绝大多数引用都是强引用;而其他几种引用则是JDK 1.2引进的,通过这些新引入的引用可以在用户代码中实现类似“感知到对象被回收从而做一些额外工作”的效果。

新引入的引用是java.lang.Reference类的子类(强引用则不是),其间的关系如下:

Java Reference 原理

注:

强引用没有对应的类型表示,也就是说强引用是普遍存在的,如Object object = new Object(); 。

直接继承java.lang.ref.Reference创建自定义的引用类型是无效的,但是可以直接继承已经存在的引用类型,如sun.misc.Cleaner就是继承自java.lang.ref.PhantomReference。 

FinalReference 是package private的作用域的,因此 FinalReference、Finalizer 都无法在用户代码中直接使用,而是由JVM去创建的

Cleaner位于 sun.misc 包下而非 java.lang.ref 。

 

2 引用的创建

直接定义的引用变量是强引用,如 Integer a = new Integer()  ,a是强引用。

其他几种引用则需要通过Reference子类创建,如 WeakReference<Integer> wr = new WeakReference<>(a); 。这里wr仍是强引用,wr对象内的referent成员才是弱引用。

 

3 引用对象的可达性及回收

对象间互相引用形成引用链。不同引用间的强弱关系依次是 强引用 > 软引用 > 弱引用 > 虚引用 > 终引用,如果有更强的引用关系存在,那么引用链的可达性将由更强的引用关系决定。因此,可达性就分为:

强可达:对象与GC Root间存在强引用链。例如下图的A、B。

软可达:对象与GC Root间不存在强引用链,但存在软引用链。例如下图的E。

弱可达:对象与GC Root间不存在强、软引用链,但存在弱引用链。例如下图的F、C、D。

虚可达:对象与GC Root间不存在强、软、弱引用链,但存在虚引用链。例如下图的G。

不可达:对象与GC Root间不存在任何引用链。例如下图的H、I。

Java Reference 原理

强引用(日常代码里的引用类型变量几乎都是这种引用)的对象不会被回收(严格来说也不是绝对的,如软、弱、虚引用对象内部对实际对象的引用referent也是强引用,但说强引用时一般不包括此情形),其他引用对象则可能被回收。

软引用:软引用对象在系统将要发生内存耗尽(OOM)前会被回收。示例:

 1 // VM参数:-Xmx4m -Xms4m
 2 public class SoftReferenceMain {
 3 
 4     public static void main(String[] args) throws Exception {
 5         ReferenceQueue<SoftReferenceObject> queue = new ReferenceQueue<>();
 6         SoftReferenceObject object = new SoftReferenceObject();
 7         SoftReference<SoftReferenceObject> reference = new SoftReference<>(object, queue);
 8         object = null;
 9         System.gc();
10         Thread.sleep(500);
11         System.out.println(reference.get());
12     }
13 
14     private static class SoftReferenceObject {
15 
16         int[] array = new int[120_000];
17 
18         @Override
19         public String toString() {
20             return "SoftReferenceObject";
21         }
22     }
23 }
24 // 运行后输出结果,可见GC后软引用关联的对象被回收了
25 null
SoftReferenceMain

相关文章:

  • 2022-12-23
  • 2021-10-29
  • 2022-12-23
  • 2022-12-23
  • 2021-06-23
  • 2021-08-15
  • 2021-07-22
  • 2021-07-13
猜你喜欢
  • 2021-11-07
  • 2021-08-09
  • 2021-12-23
  • 2021-05-21
  • 2022-01-08
  • 2022-12-23
相关资源
相似解决方案