MST
星途 面试题库

面试题:Java对象回收过程中对象的可达性分析原理

详细阐述Java在进行对象回收时,是如何通过可达性分析来判断对象是否可回收的,包括使用的数据结构和具体的分析流程,以及可能出现的问题及解决方案。
37.5万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

可达性分析判断对象是否可回收

  1. 数据结构
    • GC Roots:是可达性分析的起始点集合。包括虚拟机栈(栈帧中的本地变量表)中引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象、本地方法栈中JNI(即一般说的Native方法)引用的对象等。这些对象被认为是“绝对不会被回收的”。
  2. 分析流程
    • 从GC Roots集合中的每一个根对象开始,按照对象之间的引用关系,通过引用链进行遍历。
    • 能够被遍历到的对象,即从GC Roots可达的对象,被标记为“存活”,不可达的对象则被标记为“可回收”。
    • 例如,有一个对象A,它被栈帧中的本地变量表引用,那么A就是从GC Roots可达的,在可达性分析中会被标记为存活。如果对象B没有任何从GC Roots出发的引用链与之相连,那么B就是不可达的,会被标记为可回收。
  3. 可能出现的问题及解决方案
    • 问题
      • 对象的自我救赎:在可达性分析后,对象被判定为不可达,但对象可能覆盖了finalize()方法,并且在该方法中重新与GC Roots建立了连接,从而“复活”。这种情况可能导致对象本应被回收却没有被回收。
      • 对象的循环引用:两个或多个对象相互引用,形成一个封闭的引用环,而环中的对象都没有与GC Roots相连。从整体上看,这些对象是不可达的,但传统的可达性分析可能会误判它们为存活对象。
    • 解决方案
      • 针对对象的自我救赎:Java虚拟机对finalize()方法的调用是有且仅有一次。如果某个对象在第一次被判定为不可达时,通过finalize()方法重新可达,那么在后续再次被判定为不可达时,不会再调用finalize()方法,直接回收该对象。
      • 针对对象的循环引用:在可达性分析算法中,基于引用链遍历的方式,不会因为对象之间的循环引用而误判对象存活。只要从GC Roots出发无法到达的对象,无论是否存在循环引用,都会被判定为可回收对象。例如,对象C和对象D相互引用,但如果它们都没有从GC Roots出发的引用链相连,那么在可达性分析时,C和D都会被标记为可回收。