jvm中的可达性分析是怎么做的?

在JVM(Java虚拟机)中,可达性分析是垃圾回收器判断对象是否存活的核心算法之一。以下是对JVM中可达性分析的具体做法的详细解释:

一、可达性分析的基本概念

可达性分析算法通过一系列的“GC Roots”(垃圾回收根对象)作为起始点,向下搜索,搜索所走过的路径称为引用链。当一个对象到“GC Roots”没有任何引用链相连时,则证明此对象是不可用的,可被回收。

二、GC Roots的确定

GC Roots是可达性分析算法的起始点,它们通常包括以下几类对象:

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象。
  2. 方法区中类静态属性引用的对象。
  3. 方法区中常量引用的对象。
  4. 本地方法栈中JNI(即一般说的Native方法)引用的对象。
  5. Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如:NPE),类加载器等等。
  6. 所有被同步锁(monitor锁)持有的对象。
  7. 反应Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。

三、可达性分析的步骤

  1. 标记阶段:从GC Roots开始,使用图遍历算法(如深度优先搜索DFS或广度优先搜索BFS)遍历对象引用图,找到所有可达对象,并将它们标记为“活跃”状态。标记通常通过在对象头部设置标志位来实现。
  2. 清除阶段:遍历堆中的所有对象,回收那些未被标记(即“不活跃”)的对象。这些对象被视为不可达,可以被垃圾收集器回收。

四、三色标记法

在现代JVM中,为了优化可达性分析算法的性能,通常会采用并发标记-清除算法。这些算法允许应用线程和垃圾收集线程同时工作,以减少垃圾收集带来的暂停时间(Stop-The-World)。三色标记法是并发标记的一种实现方式,它将对象标记为以下三种颜色:

  1. 白色:尚未访问的对象。
  2. 灰色:已访问但未处理完引用的对象。
  3. 黑色:已访问且引用已处理完的对象。

在并发标记过程中,JVM会按照以下步骤进行:

  1. 初始标记:标记从GC Roots直接可达的对象,通常会短暂暂停所有应用线程。
  2. 并发标记:与应用线程并发运行,标记所有可达对象。此时,对象可能从白色变为灰色,再从灰色变为黑色。
  3. 最终标记:处理并发标记期间产生的引用变化,通常会有短暂停顿。这是为了确保在并发标记过程中新产生的引用关系能够被正确处理。
  4. 清除阶段:回收未被标记(即白色)的对象。

五、注意事项

  1. 对象的finalization机制:Java语言提供了对象终止(finalization)机制,允许开发人员提供对象被销毁之前的自定义处理逻辑。当垃圾回收器发现没有引用指向一个对象时,会先调用这个对象的finalize()方法(如果该方法存在且尚未被调用过)。然而,finalize()方法的执行时间是没有保障的,且一个糟糕的finalize()会严重影响GC的性能。因此,通常不建议依赖finalize()方法来进行资源释放或清理工作。
  2. 避免过多的对象引用:过多的对象引用关系会增加可达性分析算法的复杂性和执行时间。因此,在编程时应尽量避免不必要的对象引用和循环引用。

综上所述,JVM中的可达性分析算法通过从GC Roots开始遍历对象引用图来标记和判断对象是否可达。该算法是垃圾回收器判断对象是否存活的重要依据之一,对于优化JVM性能和减少内存泄漏具有重要意义。