跳到主要内容

JVM 可达性分析法

1. 前言

上节课我们结束了运行时数据区的讲解,本节课程开始,我们来对执行引擎进行讲解,在执行引擎模块中,首当其冲的就是垃圾回收器。本节主要知识点如下:

  • 了解垃圾回收器在 JVM 整体架构中的位置,为本节基础知识;
  • 了解并掌握垃圾回收器的定义以及意义,为本节基础知识;
  • 理解并掌握可达性分析法的原理以及意义,为本节课程的核心知识点。

2. 垃圾回收器的位置

我们在 JVM 整体架构介绍的小节提到过 JVM 的垃圾回收器位于执行引擎中。而当时我们的执行引擎只是简单的画了下,那么我们先来看下执行引擎的更细致的结构如下图:

图片描述

Tips:在讲解可达性分析之前,我们先来解决一些基本问题:什么是垃圾回收器?为什么进行垃圾回收?哪些内存需要回收?

3. 垃圾回收器的基本概念

什么是垃圾回收器:JVM 为 Java 提供了垃圾回收机制,其实是一种偏自动的内存管理机制。简单来说,垃圾回收器会自动追踪所有正在使用的对象,并将其余未被使用的对象标记为垃圾,不需要开发者手动进行垃圾回收,JVM 自动进行垃圾回收,释放内容。

为什么进行垃圾回收:如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收。除非内存无限大,我们可以任性的分配不回收,但是事实并非如此。所以,垃圾回收是必须的。

哪些内存需要回收:哪些内存需要回收是垃圾回收机制第一个要考虑的问题,所谓“要回收的垃圾”无非就是那些不可能再被任何途径所使用的对象。无需再使用的对象,会被标记为垃圾,等待JVM回收此部分内存。

Tips:Java中通过可达性分析法来检测对象是否为垃圾,如果不可达,则将对象标记为垃圾,会被 JVM 回收,接下来我们学习可达性分析法。

4. 可达性分析法基本原理

方法原理:通过一系列称为"GC Roots"的对象作为起始点,从这些节点向下搜索,搜索所走过的路径称为引用链(即GC Roots到对象不可达时),则证明此对象是不可用的。

那么问题又来了,如何选取 GCRoots 对象呢?在 Java 语言中,可以作为 GCRoots 的对象包括下面几种:

  • 虚拟机栈(栈帧中的局部变量区,也叫局部变量表)中引用的对象;
  • 方法区中的类静态变量属性引用的对象;
  • 方法区中常量引用的对象;
  • 本地方法栈中 JNI(Native方法)引用的对象。

Tips:看了如上的原理与 GC Roots 选择的描述,感觉概念性问题比较抽象,难于理解,我们继续通过示例来进一步理解可达性分析法。

4. 可达性分析法示例

上文中提到了,可达性分析法是通过 GC Roots 为起点的搜索,有四种对象可以作为 GC Roots,那么我们通过如下示意图来理解下,何为不可达对象。

图片描述

GC Roots 四种类型解释:从上图中,我们可以看到四种 GC Roots。这里我们对这四种 GC Roots 做一下更为细致的解释。

  • 虚拟机栈中的引用的对象:我们在程序中正常创建一个对象,对象会在堆上开辟一块空间,同时会将这块空间的地址作为引用保存到虚拟机栈中,如果对象生命周期结束了,那么引用就会从虚拟机栈中出栈,因此如果在虚拟机栈中有引用,就说明这个对象还是有用的,这种情况是最常见的;
  • 全局的静态的对象:也就是使用了 static 关键字,由于虚拟机栈是线程私有的,所以这种对象的引用会保存在共有的方法区中,显然将方法区中的静态引用作为 GC Roots 是必须的;
  • 常量引用:就是使用了 static final 关键字,由于这种引用初始化之后不会修改,所以方法区常量池里的引用的对象也应该作为 GC Roots;
  • Native 方法引用对象:这一种是在使用 JNI 技术时,有时候单纯的 Java 代码并不能满足我们的需求,我们可能需要在 Java 中调用 C 或 C++ 的代码,因此会使用 native 方法,JVM 内存中专门有一块本地方法栈,用来保存这些对象的引用,所以本地方法栈中引用的对象也会被作为 GC Roots。

从上图来理解可达性分析法就会非常简单,四种 GC Roots 无非是 Java 中的引用对象,从GC Roots 出发,类似于我们使用开发工具看代码,发现某部分代码用不到了,我们就会删除这部分代码。其实可达性分析法也是如此,发现某些对象不可达了,就会被垃圾回收器收集。

从上图中来看,对象 A,B,C,D,E,F 为可达对象;而对象 G,H,I,J,K 为不可达对象,会被标记为垃圾对象,最终被垃圾回收器回收。

5. 小结

本节讲解了垃圾回收回收器的定义以及垃圾回收器存在的意义,并在此基础上讲解了垃圾回收器是如何判定对象的可达性的。可达性分析法是本节的核心知识点,是必须要掌握的知识点。

在讲解 GC Roots 的知识点时,我们总是会使用 “引用对象” 这四个字,其中引用又分为 4 种引用,下节课程我们会详细的讲解。