📘 本文为「Java 模拟面试总结系列」的第 2 篇,基于我与 ChatGPT 进行的模拟问答过程整理而成,专注于 Java 面试中最核心的模块之一 —— JVM。
内容覆盖 JVM 架构、内存模型、类加载机制、GC 回收策略、性能调优 等高频面试知识点,并配以标准问答与解析,适合系统复习。
本篇主题:JVM 面试题与知识点详解
# 📌 导航:
[TOC]
# 📚 Java 模拟面试系列目录:
- Java 基础与进阶
- JVM 面试题与知识点详解
- 并发编程与锁机制
- MySQL 与 SQL 优化
- Spring 核心原理
- 系统设计与高并发架构
- Redis 高级特性
- 注册中心与微服务治理
- 项目实战与系统架构设计
# ❓ 面试题目 1:简述 JVM 的内存结构及各部分作用?
# ✅ 标准回答:
JVM 内存结构主要包括以下几个区域:
| 区域名 | 说明 |
|---|---|
| 程序计数器 | 当前线程所执行的字节码行号指示器,是线程私有的 |
| Java 虚拟机栈 | 保存局部变量表、操作数栈、方法出口等,是线程私有的 |
| 本地方法栈 | 为虚拟机使用到的 Native 方法服务 |
| Java 堆 | 所有线程共享的内存区域,用于存储对象实例 |
| 方法区(元空间) | 用于存储类信息、常量、静态变量等,是线程共享的 |
# ❓ 面试题目 2:如何判断一个对象可以被 GC 回收?
# ✅ 标准回答:
JVM 中主要有两种方式判断对象是否可以回收:
- 引用计数法:对象拥有引用计数器,引用 + 1、释放 - 1,计数为 0 即回收(但容易产生循环引用问题)
- 可达性分析算法(Reachability Analysis):从 “GC Root” 出发向下搜索,无法与 GC Root 连接的对象即为 “不可达对象”,可被回收。
GC Root 包括:虚拟机栈中引用的对象、方法区静态字段、常量引用对象、本地方法栈中引用对象等。
# ❓问题 3:Java 中的类加载机制是怎样的?双亲委派模型是什么?
# ✅ Java 类加载的生命周期阶段
- 加载(Loading)
- 通过类的全限定名获取字节码(二进制流),并生成
Class对象。
- 通过类的全限定名获取字节码(二进制流),并生成
- 验证(Verification)
- 校验字节码的正确性和安全性,防止恶意代码破坏虚拟机安全。
- 准备(Preparation)
- 给类的静态变量分配内存并赋默认值。
- 解析(Resolution)
- 把符号引用转为直接引用(如方法、字段等的内存地址)。
- 初始化(Initialization)
- 执行类的初始化代码,包括静态变量的赋值和静态代码块。
- 使用(Using)
- 类被调用(new 实例、调用静态方法等)。
- 卸载(Unloading)
- 类从内存中卸载,通常由 JVM 垃圾回收机制决定。
# ✅ 双亲委派模型(Parent Delegation Model)
- 类加载器在加载类时,先将请求委派给父加载器。
- 流程:
当前类加载器接到加载请求,先让父类加载器尝试加载。
如果父加载器找不到,当前加载器才自己尝试加载。
# ✅ 设计目的和好处
- 防止重复加载同一个类,保证 Java 核心类库的安全。
- 保证核心类库由启动类加载器加载,避免用户自定义类覆盖核心类。
# ✅简短回答示范:
- 类加载包括加载、验证、准备、解析、初始化、使用、卸载。
- 双亲委派模型:请求先委托给父加载器,父加载器找不到才自己加载,保证核心类安全。
# ❓问题 4:谈谈你对 Java 内存泄漏的理解,常见原因和排查方法有哪些?
# ✅ 什么是内存泄漏?
- 内存泄漏指程序中不再使用的对象仍然被引用,导致垃圾回收器无法回收,从而导致可用内存减少,最终可能导致应用内存溢出(OOM)。
# ✅ Java 中内存泄漏常见原因
- 长生命周期对象持有短生命周期对象引用
例如:- 静态集合(
static List)不断往里添加对象,但没有清理; - 线程池、缓存持有对象,导致对象无法被回收。
- 静态集合(
- 监听器或回调未注销
- 注册了事件监听器或观察者,但没有取消,导致对象无法被回收。
- 内部类和匿名类持有外部类引用
- 导致外部类对象无法回收。
- 数据库连接、IO 流未关闭
- 资源没有释放,导致内存和资源泄漏。
- 线程未正确结束
- 线程还活着,线程内持有对象,无法回收。
# ✅ 内存泄漏的排查方法
- 使用内存分析工具
- 如
VisualVM、Eclipse MAT、JProfiler、YourKit等。
- 如
- 堆转储(Heap Dump)分析
- 生成堆快照,分析哪些对象占用大量内存,找到引用链。
- 代码审查
- 检查静态变量、集合、缓存的使用。
- 增加日志和监控
- 监控 JVM 内存使用、GC 日志。
# ✅总结:
- 内存泄漏是无用对象被引用无法回收。
- 常见原因:静态集合无清理,监听器未注销,线程未结束等。
- 排查用 VisualVM、MAT、代码审查。
# ✅ 简短示范回答
Java 内存泄漏是指不再使用的对象被持续引用,导致垃圾回收无法回收,最终可能发生内存溢出。常见原因包括静态集合无限制增长、监听器未注销、线程未关闭等。排查方法有使用 VisualVM、MAT 等工具分析堆内存,结合代码审查定位问题。
# ❓问题 5:Java 垃圾回收原理和常见回收器?
# ✅ Java 垃圾回收(GC)基本原理
- Java 的垃圾回收机制自动管理内存,主要目的是回收不再使用的对象,释放内存,避免内存泄漏和溢出。
- JVM 堆内存分为年轻代(Young Generation)** 和 ** 老年代(Old Generation)。
- 新生代采用复制算法(Copying),老年代采用标记 - 整理算法(Mark-Compact)。
- 垃圾回收的核心思想是可达性分析:从 GC Roots 开始,所有无法被访问的对象视为垃圾。
# ✅ 常见的垃圾回收器及适用场景
| 垃圾回收器 | 简介 | 适用场景 |
|---|---|---|
| Serial(串行收集器) | 单线程执行,简单高效,停顿时间长 | 单核 CPU,客户端应用,低内存环境 |
| Parallel(并行收集器) | 多线程执行,注重吞吐量,停顿较短 | 多核 CPU,后台批处理,吞吐量优先 |
| CMS(并发标记清除) | 并发回收,停顿短,但 CPU 占用高 | 需要低停顿的应用,如 Web 服务器 |
| G1(Garbage-First) | 以区域为单位回收,低延迟、可预测停顿 | 多核大内存服务器,需响应时间可控的场景 |
| ZGC / Shenandoah | 低延迟、几乎不暂停的垃圾回收器 | 大内存超低延迟应用(JDK 11+ / 12+) |
# ✅ 简短答法示范
Java GC 自动管理内存,主要通过可达性分析判断对象是否可回收。堆内存分为年轻代和老年代,分别用不同算法回收。常见回收器有串行、并行、CMS 和 G1,选择时根据应用对吞吐量和延迟的需求权衡。
# ✅答案:
- GC 自动回收无用对象,堆分年轻代和老年代。
- 常用回收器:Serial、Parallel、CMS、G1、ZGC 等。
- 选择依据应用延迟和吞吐需求。
👉 后续面试题包括:
- CMS 和 G1 有哪些区别?
- 类加载器有哪些?如何打破双亲委派?
- 如何查看 GC 日志,常用 JVM 启动参数有哪些?
- ……
✍️ 如果你对 JVM 有深入实践或调优经验,也欢迎评论交流你的理解与踩坑经历。
📖 敬请期待下一篇:《并发编程与锁机制》