← 每日面试题 学习看板

JVM如何判断对象是否存活?

面试题/00java/03JVM/04垃圾回收(GC)基础/JVM如何判断对象是否存活?.md

面试记录 2026-09-21

题目:JVM如何判断对象是否存活?

难度:medium

标签:jvm/gc, general/knowledge, difficulty/medium

评分:⭐⭐⭐☆☆(3/5)

我的回答

JVM 判断机器存活的核心方式目前主要是根节点法,也就是 root 节点法,就是判断根节点。JVM 这个对象是否被根节点有相关的引用。我这些根节点 root 节点主要包括静态方法、当前运行的线程方法、主线程方法,对应的其中的对象、静态的对象,常量、静态常量,类加载器,这些东西。

点评

优点:

不足:

补充:

完整讲解

第一部分:知识重点剖析

核心考点定位:考察 GC 存活判断的两种主流算法 + GC Roots 完整清单 + 分代假设的工程含义。

知识点拆解:

  1. 两种判断算法
  1. GC Roots 完整清单(HotSpot 实现)
  1. 对象"不可达"不等于"已死"
  1. 分代假设

第二部分:考察方向与延伸递进

考察方向:

延伸递进面试题:

  1. 引用计数法在什么语言中还在用?为什么?
  1. finalize() 有什么坑?为什么被弃用?
  1. 如何用 MAT 排查内存泄漏?
  1. 弱分代假设对 GC 策略有什么影响?

第三部分:面试者参考回答(300-600 字口语化)

面试官您好,JVM 判断对象存活主要用可达性分析,不是引用计数。

先说为什么不用引用计数:每个对象维护一个引用计数,被引用 +1,解除引用 -1,为 0 就回收。但循环引用会死锁——A 引用 B、B 引用 A,即使外部都不引用了,两者计数都非 0,永远回收不了。所以 Java、Python、JavaScript 都放弃了引用计数,只用可达性分析。Objective-C ARC 阶段用过引用计数,但也是通过 weak 属性来打破循环。

可达性分析的核心是从一组 GC Roots 出发遍历引用链,能到达的对象存活,到不了的回收。GC Roots 包括:

  1. 栈引用:所有活跃线程栈帧的局部变量、方法参数、运算栈
  2. 静态字段:类的 static 变量
  3. 常量池引用:运行时常量池里的类引用
  4. synchronized 持有的对象(监视器锁对象)
  5. JNI 引用:本地方法持有的 Java 对象
  6. 类加载器 + JVM 内部引用(GC 实现细节)

这里有个补充点:对象"不可达"不等于"已死"。如果重写了 finalize() 且还没调用过,GC 会把它放到 F-Queue,让"自救线程"执行 finalize;在 finalize 里重新赋值给变量就能回到可达,但只有一次机会。JDK 9 之后 finalize 被弃用,改用 Cleaner 机制(基于虚引用 + ReferenceQueue),更可控也更快。

最后要提到分代假设——这是从"存活判断"过渡到"GC 策略选择"的桥梁:几乎所有对象朝生夕死,熬过几次 GC 的对象更难死。所以新生代小、GC 频繁但快(复制算法),老年代大、GC 少而慢(标记-整理)。这就是为什么 JVM 要分代。