【面试专栏|JVM虚拟机】JVM垃圾回收入门:对象死亡判断的底层逻辑

【面试专栏|JVM虚拟机】JVM垃圾回收入门:对象死亡判断的底层逻辑

在这里插入图片描述


🍃 予枫个人主页
📚 个人专栏: 《Java 从入门到起飞》《读研码农的干货日常》《Java 面试刷题指南

💻 Debug 这个世界,Return 更好的自己!


引言

作为Java程序员,JVM垃圾回收机制是面试绕不开的高频考点,而“如何判断对象死亡”更是基础中的基础。很多人只记结论却不懂底层逻辑,面试时被面试官追问就慌了阵脚。本文将从原理出发,拆解对象死亡的2种核心判断方式,补充面试高频追问,帮你吃透考点、轻松应答,建议收藏备用!

文章目录

一、为什么要判断对象死亡?

在JVM中,内存资源是有限的,尤其是堆内存(存储对象实例的核心区域)。如果创建的对象不再被使用,却一直占用内存,久而久之会导致内存泄漏,甚至触发OOM(OutOfMemoryError)异常,导致程序崩溃。

因此,JVM垃圾回收的核心前提的是:准确判断哪些对象已经“死亡”(不再被任何地方引用,失去使用价值) ,才能安全地回收其占用的内存,保证程序稳定运行。

简单来说:判断对象死亡,是垃圾回收的“前置操作”,也是避免内存浪费的关键。

二、对象死亡判断的2大核心机制

JVM判断对象死亡,主要依赖两种机制:引用计数法可达性分析算法。其中,可达性分析算法是目前JVM主流采用的核心方式,而引用计数法因自身缺陷被淘汰,我们逐一拆解。

2.1 引用计数法(已淘汰)

原理

给每个对象分配一个“引用计数器”,当对象被引用一次,计数器值加1;当引用失效(比如变量赋值为null),计数器值减1。当计数器值为0时,认为该对象已经死亡,可被回收。

示例(伪代码)

// 创建对象,计数器=1Object obj =newObject();// 新增引用,计数器=2Object obj2 = obj;// 引用失效,计数器=1 obj =null;// 引用失效,计数器=0(对象可被回收) obj2 =null;

致命缺陷:循环引用问题

引用计数法最大的问题的是无法解决“循环引用”场景,这也是它被JVM淘汰的核心原因。

比如两个对象互相引用,但都不再被其他地方引用,此时它们的计数器值都为1,无法被回收,导致内存泄漏:

classA{privateB b;publicvoidsetB(B b){this.b = b;}}classB{privateA a;publicvoidsetA(A a){this.a = a;}}// 循环引用A a =newA();B b =newB(); a.setB(b); b.setA(a);// 引用失效,但计数器都为1,无法回收 a =null; b =null;

正因为这个缺陷,目前主流JVM(如HotSpot)均未采用引用计数法,而是选择了可达性分析算法。

2.2 可达性分析算法(主流核心)

原理

以“GC Roots”(垃圾回收根节点)为起点,向下遍历所有引用链(引用关系)。如果一个对象没有任何一条引用链连接到GC Roots,则认为该对象不可达,标记为“可回收对象”(并非立即死亡,还需经过二次标记)。

简单来说:GC Roots是“不会被回收”的核心对象,从这些对象出发,能找到的对象都是“存活”的,找不到的就是“待回收”的。

第一步:明确GC Roots的组成(面试高频考点)

GC Roots必须是“绝对不会被垃圾回收”的对象,主要包括以下4类(记牢,面试常问):

  1. 虚拟机栈(栈帧中的局部变量表)中引用的对象(比如方法内定义的局部变量);
  2. 方法区中类静态属性引用的对象(比如static修饰的变量);
  3. 方法区中常量引用的对象(比如final修饰的常量);
  4. 本地方法栈中JNI(Native方法)引用的对象。

第二步:可达性分析流程(附流程图)

GC Roots

对象1

对象2

对象3

对象4

对象5

对象6

对象5、6无引用链连接到GC Roots,标记为可回收

流程拆解:

  1. 确定GC Roots集合(上述4类对象);
  2. 从GC Roots出发,遍历所有引用关系,形成“存活对象引用链”;
  3. 未被引用链覆盖的对象,标记为“不可达对象”,进入待回收队列。

第三步:对象死亡的最终确认(二次标记)

不可达对象并非立即死亡,还需经过“二次标记”才能确认死亡:

  1. 第一次标记:通过可达性分析,标记为不可达对象;
  2. 筛选判断:检查该对象是否重写了finalize()方法,且该方法未被执行过;
    • 若未重写finalize(),或已执行过,则直接标记为“死亡对象”;
    • 若重写了且未执行,则将对象放入“F-Queue”队列,由虚拟机自动执行finalize()方法;
  3. 二次标记:执行完finalize()方法后,再次判断对象是否可达。若仍不可达,则正式标记为死亡对象;若重新变得可达(比如在finalize()中重新建立引用),则移除待回收队列,继续存活。

⚠️ 注意:finalize()方法是对象“最后的自救机会”,但实际开发中不建议使用(执行时机不确定、效率低,还可能导致内存泄漏),JDK9已标记为过时方法。

三、面试官追问环节(实战价值拉满)

这部分是面试加分项,帮你提前应对面试官的连环追问,比纯记八股更有用!

追问1:JVM为什么不采用引用计数法,而是选择可达性分析算法?

答:核心原因是引用计数法无法解决“循环引用”问题,会导致内存泄漏;而可达性分析算法通过GC Roots为起点,能完美避开循环引用的坑(循环引用的对象无法连接到GC Roots,会被标记为不可达)。此外,可达性分析算法的判断逻辑更严谨,能更准确地识别存活对象。

追问2:GC Roots具体包含哪些对象?有没有补充的?

答:核心是4类(虚拟机栈局部变量、方法区静态属性、方法区常量、本地方法栈JNI引用),补充2类特殊情况:

  • 被同步锁(synchronized)持有的对象;
  • JVM内部的对象(比如类加载器、系统类、常驻内存的对象)。

追问3:对象被标记为不可达后,为什么不立即回收?

答:为了给对象一次“自救”的机会,即通过finalize()方法重新建立引用,避免误回收(虽然实际开发中很少用,但JVM设计时保留了这个机制)。同时,批量回收不可达对象能提高垃圾回收的效率,避免频繁触发回收操作。

追问4:finalize()方法能真正让对象“自救”吗?为什么不推荐使用?

答:理论上可以(在finalize()中给对象重新赋值,建立到GC Roots的引用),但实际不推荐,原因有3点:

  1. 执行时机不确定:finalize()由JVM的Finalizer线程执行,线程优先级低,无法保证及时执行;
  2. 效率低:Finalizer线程执行速度慢,大量使用会拖慢垃圾回收效率;
  3. 易导致内存泄漏:若finalize()中出现异常,对象无法被回收,长期积累会导致内存泄漏。

四、总结

本文核心讲解了JVM判断对象死亡的2种机制,重点掌握可达性分析算法(GC Roots、引用链遍历、二次标记),这是面试的核心考点。

核心要点总结:

  1. 判断对象死亡是垃圾回收的前提,避免内存泄漏和OOM;
  2. 引用计数法因循环引用缺陷被淘汰;
  3. 可达性分析算法是主流,核心是GC Roots和引用链遍历;
  4. 不可达对象需经过二次标记,finalize()可自救但不推荐使用。

建议结合本文的面试追问,反复梳理原理,面试时才能从容应答。觉得有用的话,点赞+收藏,后续持续更新JVM面试干货!

Read more

深挖 DeepSeek 隐藏玩法·智能炼金术2.0版本

深挖 DeepSeek 隐藏玩法·智能炼金术2.0版本

前引:屏幕前的你还在AI智能搜索框这样搜索吗?“这道题怎么写”“苹果为什么红”“怎么不被发现翘课” ,。看到此篇文章的小伙伴们!请准备好你的思维魔杖,开启【霍格沃茨模式】,看我如何更新秘密的【知识炼金术】,我们一起来解锁更加刺激的剧情!友情提醒:《《《前方高能》》》 目录 在哪使用DeepSeek 如何对提需求  隐藏玩法总结 几个高阶提示词 职场打工人 自媒体创作 电商实战 程序员开挂 非适用场地 “服务器繁忙”如何解决 (1)硅基流动平台 (2)Chatbox + API集成方案 (3)各大云平台 搭建个人知识库 前置准备 下载安装AnythingLLM 选择DeepSeek作为AI提供商 创作工作区 导入文档 编辑  编辑 小编寄语 ——————————————————————————————————————————— 在哪使用DeepSeek 我们解锁剧情前,肯定要知道在哪用DeepSeek!咯,为了照顾一些萌新朋友,它的下载方式我放在下面了,拿走不谢!  (1)

By Ne0inhk
【AI大模型】DeepSeek + 通义万相高效制作AI视频实战详解

【AI大模型】DeepSeek + 通义万相高效制作AI视频实战详解

目录 一、前言 二、AI视频概述 2.1 什么是AI视频 2.2 AI视频核心特点 2.3 AI视频应用场景 三、通义万相介绍 3.1 通义万相概述 3.1.1 什么是通义万相 3.2 通义万相核心特点 3.3 通义万相技术特点 3.4 通义万相应用场景 四、DeepSeek + 通义万相制作AI视频流程 4.1 DeepSeek + 通义万相制作视频优势 4.1.1 DeepSeek 优势 4.1.2 通义万相视频生成优势 4.2

By Ne0inhk
【DeepSeek微调实践】DeepSeek-R1大模型基于MS-Swift框架部署/推理/微调实践大全

【DeepSeek微调实践】DeepSeek-R1大模型基于MS-Swift框架部署/推理/微调实践大全

系列篇章💥 No.文章01【DeepSeek应用实践】DeepSeek接入Word、WPS方法详解:无需代码,轻松实现智能办公助手功能02【DeepSeek应用实践】通义灵码 + DeepSeek:AI 编程助手的实战指南03【DeepSeek应用实践】Cline集成DeepSeek:开源AI编程助手,终端与Web开发的超强助力04【DeepSeek开发入门】DeepSeek API 开发初体验05【DeepSeek开发入门】DeepSeek API高级开发指南(推理与多轮对话机器人实践)06【DeepSeek开发入门】Function Calling 函数功能应用实战指南07【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:本地部署与API服务快速上手08【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:Web聊天机器人部署指南09【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:基于vLLM 搭建高性能推理服务器10【DeepSeek部署实战】基于Ollama快速部署Dee

By Ne0inhk

DeepSeek各版本说明与优缺点分析_deepseek各版本区别

DeepSeek各版本说明与优缺点分析 DeepSeek是最近人工智能领域备受瞩目的一个语言模型系列,其在不同版本的发布过程中,逐步加强了对多种任务的处理能力。本文将详细介绍DeepSeek的各版本,从版本的发布时间、特点、优势以及不足之处,为广大AI技术爱好者和开发者提供一份参考指南。 1. DeepSeek-V1:起步与编码强劲 DeepSeek-V1是DeepSeek的起步版本,这里不过多赘述,主要分析它的优缺点。 发布时间: 2024年1月 特点: DeepSeek-V1是DeepSeek系列的首个版本,预训练于2TB的标记数据,主打自然语言处理和编码任务。它支持多种编程语言,具有强大的编码能力,适合程序开发人员和技术研究人员使用。 优势: * 强大编码能力:支持多种编程语言,能够理解和生成代码,适合开发者进行自动化代码生成与调试。 * 高上下文窗口:支持高达128K标记的上下文窗口,能够处理较为复杂的文本理解和生成任务。 缺点: * 多模态能力有限:该版本主要集中在文本处理上,缺少对图像、语音等多模态任务的支持。 * 推理能力较弱:尽管在自然语言

By Ne0inhk