news 2026/8/21 23:35:50

Java虚拟机面试题:垃圾收集(上)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java虚拟机面试题:垃圾收集(上)

🧑 博主简介:CSDN博客专家历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程高并发设计Springboot和微服务,熟悉LinuxESXI虚拟化以及云原生Docker和K8s,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作请加本人wx(注明来自csdn):foreast_sea


Java虚拟机面试题:垃圾收集(上)

1. 讲讲 JVM 的垃圾回收机制

垃圾回收就是对内存堆中已经死亡的或者长时间没有使用的对象进行清除或回收。

JVM 在做 GC 之前,会先搞清楚什么是垃圾,什么不是垃圾,通常会通过可达性分析算法来判断对象是否存活。

在确定了哪些垃圾可以被回收后,垃圾收集器(如 CMS、G1、ZGC)要做的事情就是进行垃圾回收,可以采用标记清除算法、复制算法、标记整理算法、分代收集算法等。

2. 如何判断对象仍然存活?

通常有两种方式:引用计数算法和可达性分析算法,Java 使用的是可达性分析算法。

什么是引用计数法?

每个对象有一个引用计数器,记录引用它的次数。当计数器为零时,对象可以被回收。

但无法解决循环引用问题。例如,两个对象互相引用,但不再被其他对象引用,它们的引用计数都不为零,因此不会被回收。

什么是可达性分析算法?

通过一组名为 “GC Roots” 的根对象,进行递归扫描。那些无法从根对象到达的对象是不可达的,可以被回收;反之,是可达的,不会被回收。


这也是 G1、CMS 等主流垃圾收集器使用的主要算法。

做可达性分析的时候,应该有哪些前置性的操作?

在进行垃圾回收之前,JVM 会暂停所有正在执行的应用线程(称为 Stop-the-World)。

这是因为可达性分析过程必须确保在执行分析时,内存中的对象关系不会被应用线程修改。如果不暂停应用线程,可能会出现对象引用的改变,导致垃圾回收过程中判断对象是否可达的结果不一致,从而引发严重的内存错误或数据丢失。

3. Java 中可作为 GC Roots 的引用有哪几种?

所谓的 GC Roots,就是一组必须活跃的引用,不是对象,它们是程序运行时的起点,是一切引用链的源头。在 Java 中,GC Roots 包括以下几种:

  • 虚拟机栈中的引用(方法的参数、局部变量等)
  • 本地方法栈中 JNI 的引用
  • 类静态变量
  • 运行时常量池中的常量(String 或 Class 类型)

1、虚拟机栈中的引用(方法的参数、局部变量等)

来看下面这段代码:

publicclassStackReference{publicvoidgreet(){ObjectlocalVar=newObject();// 这里的 localVar 是一个局部变量,存在于虚拟机栈中System.out.println(localVar.toString());}publicstaticvoidmain(String[]args){newStackReference().greet();}}

在 greet 方法中,localVar 是一个局部变量,存在于虚拟机栈中,可以被认为是 GC Roots。

在 greet 方法执行期间,localVar 引用的对象是活跃的,因为它是从 GC Roots 可达的。

当 greet 方法执行完毕后,localVar 的作用域结束,localVar 引用的 Object 对象不再由任何 GC Roots 引用(假设没有其他引用指向这个对象),因此它将有资格作为垃圾被回收掉 😁。

2、本地方法栈中 JNI 的引用

Java 通过 JNI(Java Native Interface)提供了一种机制,允许 Java 代码调用本地代码(通常是 C 或 C++ 编写的代码)。

当调用 Java 方法时,虚拟机会创建一个栈帧并压入虚拟机栈,而当它调用本地方法时,虚拟机会通过动态链接直接调用指定的本地方法。

JNI 引用是在 Java 本地接口(JNI)代码中创建的引用,这些引用可以指向 Java 堆中的对象。

// 假设的JNI方法publicnativevoidnativeMethod();// 假设在C/C++中实现的本地方法/* * Class: NativeExample * Method: nativeMethod * Signature: ()V */JNIEXPORTvoidJNICALLJava_NativeExample_nativeMethod(JNIEnv*env,jobject thisObj){jobject localRef=(*env)->NewObject(env,...);// 在本地方法栈中创建JNI引用// localRef 引用的Java对象在本地方法执行期间是活跃的}

在本地(C/C++)代码中,localRef 是对 Java 对象的一个 JNI 引用,它在本地方法执行期间保持 Java 对象活跃,可以被认为是 GC Roots。

一旦 JNI 方法执行完毕,除非这个引用是全局的(Global Reference),否则它指向的对象将会被作为垃圾回收掉(假设没有其他地方再引用这个对象)。

3、类静态变量

来看下面这段代码:

publicclassStaticFieldReference{privatestaticObjectstaticVar=newObject();// 类静态变量publicstaticvoidmain(String[]args){System.out.println(staticVar.toString());}}

StaticFieldReference 类中的 staticVar 引用了一个 Object 对象,这个引用存储在元空间,可以被认为是 GC Roots。

只要 StaticFieldReference 类未被卸载,staticVar 引用的对象都不会被垃圾回收。如果 StaticFieldReference 类被卸载(这通常发生在其类加载器被垃圾回收时),那么 staticVar 引用的对象也将有资格被垃圾回收(如果没有其他引用指向这个对象)。

4、运行时常量池中的常量

来看这段代码:

publicclassConstantPoolReference{publicstaticfinalStringCONSTANT_STRING="Hello, World";// 常量,存在于运行时常量池中publicstaticfinalClass<?>CONSTANT_CLASS=Object.class;// 类类型常量publicstaticvoidmain(String[]args){System.out.println(CONSTANT_STRING);System.out.println(CONSTANT_CLASS.getName());}}

在 ConstantPoolReference 中,CONSTANT_STRING 和 CONSTANT_CLASS 作为常量存储在运行时常量池。它们可以用来作为 GC Roots。

这些常量引用的对象(字符串"Hello, World"和 Object.class 类对象)在常量池中,只要包含这些常量的 ConstantPoolReference 类未被卸载,这些对象就不会被垃圾回收。

4. finalize()方法了解吗?有什么作用?

用一个不太贴切的比喻,垃圾回收就是古代的秋后问斩,finalize()就是刀下留人,在人犯被处决之前,还要做最后一次审计,青天大老爷看看有没有什么冤情,需不需要刀下留人。

如果对象在进行可达性分析后发现没有与 GC Roots 相连接的引用链,那它将会被第一次标记,随后进行一次筛选,筛选的条件是此对象是否有必要执行 finalize()方法。如果对象在在 finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己 (this 关键字)赋值给某个类变量或者对象的成员变量,那在第二次标记时它就”逃过一劫“;但是如果没有抓住这个机会,那么对象就真的要被回收了。

5. 垃圾收集算法了解吗?

垃圾收集算法主要有三种,分别是标记-清除算法、标记-复制算法和标记-整理算法。

说说标记-清除算法?

标记-清除算法分为两个阶段:

  • 标记:标记所有需要回收的对象
  • 清除:回收所有被标记的对象

优点是实现简单,缺点是回收过程中会产生内存碎片。

说说标记-复制算法?

标记-复制算法可以解决标记-清除算法的内存碎片问题,因为它将内存空间划分为两块,每次只使用其中一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后清理掉这一块。

缺点是浪费了一半的内存空间。

说说标记-整理算法?

标记-整理算法是标记-清除复制算法的升级版,它不再划分内存空间,而是将存活的对象向内存的一端移动,然后清理边界以外的内存。

缺点是移动对象的成本比较高。

说说分代收集算法?

分代收集算法是目前主流的垃圾收集算法,它根据对象存活周期的不同将内存划分为几块,一般分为新生代和老年代。

新生代用复制算法,因为大部分对象生命周期短。老年代用标记-整理算法,因为对象存活率较高。

为什么要用分代收集呢?

分代收集算法的核心思想是根据对象的生命周期优化垃圾回收。

新生代的对象生命周期短,使用复制算法可以快速回收。老年代的对象生命周期长,使用标记-整理算法可以减少移动对象的成本。

6. Minor GC、Major GC、Mixed GC、Full GC 都是什么意思?

Minor GC 也称为 Young GC,是指发生在年轻代(Young Generation)的垃圾收集。年轻代包含 Eden 区以及两个 Survivor 区。

Major GC 也称为 Old GC,主要指的是发生在老年代的垃圾收集。CMS 收集器的特有行为。

Mixed GC 是 G1 垃圾收集器特有的一种 GC 类型,它在一次 GC 中同时清理年轻代和部分老年代。

Full GC 是最彻底的垃圾收集,涉及整个 Java 堆和方法区(元空间)。它是最耗时的 GC,通常在 JVM 压力很大时发生。

FULL gc怎么去清理的?

Full GC 会从 GC Root 出发,标记所有可达对象。新生代使用复制算法,清空 Eden 区。老年代使用标记-整理算法,回收对象并消除碎片。

停顿时间较长(STW),会影响系统响应性能。

7. Young GC 什么时候触发?

如果 Eden 区没有足够的空间时,就会触发 Young GC 来清理新生代。

8. 什么时候会触发 Full GC?

  • 在进行 Young GC 的时候,如果发现老年代可用的连续内存空间<新生代历次 Young GC 后升入老年代的对象总和的平均大小,说明本次 Young GC 后升入老年代的对象大小,可能超过了老年代当前可用的内存空间,就会触发 Full GC。
  • 执行 Young GC 后老年代没有足够的内存空间存放转入的对象,会立即触发一次 Full GC。
  • System.gc()jmap -dump等命令会触发 full gc。
空间分配担保是什么?

空间分配担保是指在进行 Minor GC(新生代垃圾回收)前,JVM 会确保老年代有足够的空间存放从新生代晋升的对象。如果老年代空间不足,可能会触发 Full GC。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/21 2:39:10

java_base_面向对象原理省流

每日一学&#xff1a;基础知识精讲ok&#xff0c;终于也是要写完了&#xff0c;真是令人激动。话不多说有请今天的主角——封装&#xff08;Encapsulation&#xff09;&#xff0c;依然用邮轮运输的场景讲透核心逻辑。封装的核心&#xff1a;“打包 控权”其本质可以总结两个方…

作者头像 李华
网站建设 2026/8/21 9:27:48

Git 开发常用命令速查手册

文章目录git命令开发最常用的核心命令一、基础配置&#xff08;首次使用必做&#xff09;二、仓库初始化和克隆1. 本地新建仓库2. 克隆远程仓库三、工作区或暂存区操作1. 查看状态&#xff08;最常用&#xff01;随时确认文件变更&#xff09;2. 添加文件到暂存区&#xff08;提…

作者头像 李华
网站建设 2026/8/20 8:05:21

如快(sofast)

链接&#xff1a;https://pan.quark.cn/s/06a8b6a75c81如快Sofast是一款致力于提升办公效率的启动器工具&#xff0c;通过简洁易用的操作界面和强大的功能&#xff0c;帮助用户快速访问应用程序和文件&#xff0c;提高工作效率。该工具支持中文拼音模糊搜索&#xff0c;方便用户…

作者头像 李华
网站建设 2026/8/21 16:37:58

Java EE 应用与 Spring MVC简介

什么是JavaEE&#xff08;j2ee&#xff09;&#xff1f;javaee是一套用于开发大型企业级应用的标准和规范。它定义了组件模型和各种API。JavaEE的分层模型JavaEE通常采用多层架构&#xff0c;将应用的关注点清晰地分离&#xff0c;我们这里介绍的层级划分为&#xff1a;Domain …

作者头像 李华
网站建设 2026/8/21 22:10:55

Buck Boost Buck-Boost

Buck 电感接在输出端&#xff0c;通过控制开关管的通断时间&#xff08;占空比D&#xff09;&#xff0c;来控制电感中存储的能量。当开关管导通时输入电压给电感储能&#xff0c;开关管关断后&#xff0c;电感释放能量到输出端&#xff0c;由于占空比D<1&#xff0c;达到降…

作者头像 李华
网站建设 2026/8/21 8:34:00

springboot基于vue的仓库管理系统 前端前台_g3y27qk1

目录已开发项目效果实现截图开发技术系统开发工具&#xff1a;核心代码参考示例1.建立用户稀疏矩阵&#xff0c;用于用户相似度计算【相似度矩阵】2.计算目标用户与其他用户的相似度系统测试总结源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&…

作者头像 李华