news 2026/6/15 20:56:36

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/6/15 15:59:08

探秘AES加密算法:多种Transformation全解析

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

作者头像 李华
网站建设 2026/6/15 14:30:14

Python 期末复习知识点汇总

Python 期末知识点汇总 本文聚焦 Python 期末考核核心知识点&#xff0c;从基础到进阶分层梳理&#xff0c;覆盖语法、数据结构、流程控制、函数、面向对象、文件操作、异常处理等高频考点&#xff0c;适合期末复习冲刺。 一、基础语法&#xff08;必考&#xff09; 1. 编码规范…

作者头像 李华
网站建设 2026/6/15 3:16:42

线程、并发与互斥:解锁多任务编程的核心逻辑

线程、并发与互斥&#xff1a;解锁多任务编程的核心逻辑 一、线程&#xff1a;多任务执行的最小单元 线程是操作系统调度的基本单位&#xff0c;它依附于进程存在&#xff0c;共享进程的内存空间&#xff08;代码段、数据段、堆等&#xff09;&#xff0c;但拥有独立的程序计数…

作者头像 李华
网站建设 2026/6/15 7:59:18

Day35文件的规范拆分和写法

credit_default_prediction/ │ ├── data/ # 数据文件夹 │ ├── raw/ # 原始数据 │ └── processed/ # 处理后的数据 │ ├── src/ # 源代码 │ ├── __init__.py │ ├── data/ …

作者头像 李华
网站建设 2026/6/15 1:28:47

GPT-5.2来了,老金详细给你说说它为什么是王

加我进AI讨论学习群&#xff0c;公众号右下角“联系方式”文末有老金的 开源知识库地址全免费昨晚凌晨2点&#xff0c;OpenAI偷偷摸摸上线了GPT-5.2。没发布会&#xff0c;没预热&#xff0c;甚至连个官方推特都没发。作为老金最喜欢的模型&#xff0c;没有之一的&#xff0c;必…

作者头像 李华
网站建设 2026/6/15 9:22:14

上海“娃哈哈”桶装水将改名 “沪小娃“ !

近日上海娃哈哈推出全新品牌 "沪小娃" 桶装水&#xff0c;说是"娃哈哈"商标授权已到期&#xff0c;且未能获得新的授权&#xff0c;被集团要求停止使用原有品牌&#xff0c;称此举是为了活下去的无奈之举&#xff0c;承认打造新品牌难度很大。普推知商标老…

作者头像 李华