📘 本文为「Java 模拟面试总结系列」的第 2 篇,基于我与 ChatGPT 进行的模拟问答过程整理而成,专注于 Java 面试中最核心的模块之一 —— JVM。
内容覆盖 JVM 架构、内存模型、类加载机制、GC 回收策略、性能调优 等高频面试知识点,并配以标准问答与解析,适合系统复习。

本篇主题:JVM 面试题与知识点详解

# 📌 导航:

[TOC]


# 📚 Java 模拟面试系列目录:

  1. Java 基础与进阶
  2. JVM 面试题与知识点详解
  3. 并发编程与锁机制
  4. MySQL 与 SQL 优化
  5. Spring 核心原理
  6. 系统设计与高并发架构
  7. Redis 高级特性
  8. 注册中心与微服务治理
  9. 项目实战与系统架构设计

# ❓ 面试题目 1:简述 JVM 的内存结构及各部分作用?

# ✅ 标准回答:

JVM 内存结构主要包括以下几个区域:

区域名 说明
程序计数器 当前线程所执行的字节码行号指示器,是线程私有的
Java 虚拟机栈 保存局部变量表、操作数栈、方法出口等,是线程私有的
本地方法栈 为虚拟机使用到的 Native 方法服务
Java 堆 所有线程共享的内存区域,用于存储对象实例
方法区(元空间) 用于存储类信息、常量、静态变量等,是线程共享的

# ❓ 面试题目 2:如何判断一个对象可以被 GC 回收?

# ✅ 标准回答:

JVM 中主要有两种方式判断对象是否可以回收:

  1. 引用计数法:对象拥有引用计数器,引用 + 1、释放 - 1,计数为 0 即回收(但容易产生循环引用问题)
  2. 可达性分析算法(Reachability Analysis):从 “GC Root” 出发向下搜索,无法与 GC Root 连接的对象即为 “不可达对象”,可被回收。

GC Root 包括:虚拟机栈中引用的对象、方法区静态字段、常量引用对象、本地方法栈中引用对象等。


# ❓问题 3:Java 中的类加载机制是怎样的?双亲委派模型是什么?

# ✅ Java 类加载的生命周期阶段

  1. 加载(Loading)
    • 通过类的全限定名获取字节码(二进制流),并生成 Class 对象。
  2. 验证(Verification)
    • 校验字节码的正确性和安全性,防止恶意代码破坏虚拟机安全。
  3. 准备(Preparation)
    • 给类的静态变量分配内存并赋默认值。
  4. 解析(Resolution)
    • 把符号引用转为直接引用(如方法、字段等的内存地址)。
  5. 初始化(Initialization)
    • 执行类的初始化代码,包括静态变量的赋值和静态代码块。
  6. 使用(Using)
    • 类被调用(new 实例、调用静态方法等)。
  7. 卸载(Unloading)
    • 类从内存中卸载,通常由 JVM 垃圾回收机制决定。

# ✅ 双亲委派模型(Parent Delegation Model)

  • 类加载器在加载类时,先将请求委派给父加载器。
  • 流程:
    当前类加载器接到加载请求,先让父类加载器尝试加载。
    如果父加载器找不到,当前加载器才自己尝试加载。

# ✅ 设计目的和好处

  • 防止重复加载同一个类,保证 Java 核心类库的安全。
  • 保证核心类库由启动类加载器加载,避免用户自定义类覆盖核心类。

# ✅简短回答示范:

  • 类加载包括加载、验证、准备、解析、初始化、使用、卸载。
  • 双亲委派模型:请求先委托给父加载器,父加载器找不到才自己加载,保证核心类安全。

# ❓问题 4:谈谈你对 Java 内存泄漏的理解,常见原因和排查方法有哪些?

# ✅ 什么是内存泄漏?

  • 内存泄漏指程序中不再使用的对象仍然被引用,导致垃圾回收器无法回收,从而导致可用内存减少,最终可能导致应用内存溢出(OOM)。

# ✅ Java 中内存泄漏常见原因

  1. 长生命周期对象持有短生命周期对象引用
    例如:
    • 静态集合( static List )不断往里添加对象,但没有清理;
    • 线程池、缓存持有对象,导致对象无法被回收。
  2. 监听器或回调未注销
    • 注册了事件监听器或观察者,但没有取消,导致对象无法被回收。
  3. 内部类和匿名类持有外部类引用
    • 导致外部类对象无法回收。
  4. 数据库连接、IO 流未关闭
    • 资源没有释放,导致内存和资源泄漏。
  5. 线程未正确结束
    • 线程还活着,线程内持有对象,无法回收。

# ✅ 内存泄漏的排查方法

  1. 使用内存分析工具
    • VisualVMEclipse MATJProfilerYourKit 等。
  2. 堆转储(Heap Dump)分析
    • 生成堆快照,分析哪些对象占用大量内存,找到引用链。
  3. 代码审查
    • 检查静态变量、集合、缓存的使用。
  4. 增加日志和监控
    • 监控 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 有深入实践或调优经验,也欢迎评论交流你的理解与踩坑经历。

📖 敬请期待下一篇:《并发编程与锁机制》