JVM 高频面试题

高频说明:这里的“高频”来自 Java 后端面试常见覆盖面整理,不代表公开统计排名;暂无来源可查。
复习方式:先背“答题模板”,再用“追问”检查自己能不能展开。

快速答题框架

  • 先讲定义:它解决什么问题。
  • 再讲机制:核心流程、关键组件、边界条件。
  • 再讲问题:常见坑、线上表现、排查工具。
  • 最后讲实践:你会怎么设置、监控、验证。

运行时内存区域

JVM 运行时数据区有哪些?

面试官想看什么

  • 是否知道线程共享区和线程私有区。
  • 是否能把“JVM 内存”和“Java 内存模型”区分开。

核心答案

  • 线程共享:堆、方法区。
  • 线程私有:虚拟机栈、本地方法栈、程序计数器。
  • 堆主要放对象实例,是 GC 管理重点。
  • 虚拟机栈存放栈帧,栈帧里有局部变量表、操作数栈、动态链接、方法返回地址。
  • 方法区存放类元数据、常量、静态变量等逻辑信息;HotSpot 在 JDK 8 后用 Metaspace 替代永久代实现。

常见追问

  • 堆和栈的区别?
  • 方法区、永久代、元空间是什么关系?
  • 程序计数器为什么线程私有?

一句话模板

JVM 运行时内存可以按线程是否共享来答:堆和方法区共享,栈、本地方法栈、程序计数器线程私有;对象主要在堆上分配,方法调用主要在线程栈上形成栈帧。


堆和栈有什么区别?

面试官想看什么

  • 是否能从生命周期、存储内容、异常、性能角度说清楚。

核心答案

  • 堆:线程共享,主要存对象实例和数组,生命周期由 GC 管理。
  • 栈:线程私有,随方法调用创建栈帧,随方法结束出栈。
  • 堆常见异常是 OutOfMemoryError;栈常见异常是 StackOverflowError 或栈内存不足导致的 OutOfMemoryError
  • 栈访问通常更直接;堆对象需要考虑逃逸、GC、引用关系。

常见追问

  • 局部变量对象一定在栈上吗?
  • 栈越大越好吗?

一句话模板

堆管对象生命周期,栈管方法调用过程;堆的问题多表现为 GC 压力和 OOM,栈的问题多表现为递归过深或线程数过多。


方法区、永久代、元空间的区别?

面试官想看什么

  • 是否知道“规范里的方法区”和“HotSpot 里的实现”不是一回事。

核心答案

  • 方法区是 JVM 规范中的运行时数据区。
  • 永久代是早期 HotSpot 对方法区的实现。
  • Metaspace 是 HotSpot 在 JDK 8 后用于存放类元数据的实现,使用本地内存。
  • 元空间不是无限的,仍然可能因为类加载过多、动态代理过多、类加载器泄漏而 OOM。

常见追问

  • 为什么移除永久代?
  • Metaspace OOM 怎么排查?

一句话模板

方法区是规范概念,永久代和元空间是 HotSpot 的实现变化;JDK 8 后类元数据主要进入本地内存里的 Metaspace。


对象与类加载

Java 对象创建过程是什么?

面试官想看什么

  • 是否理解从 class 到对象实例的完整链路。

核心答案

  • 遇到 new 时先检查类是否已加载、解析和初始化。
  • 为对象分配内存,常见方式有指针碰撞和空闲列表,取决于堆是否规整。
  • 处理并发分配问题,常见方式包括 CAS 或 TLAB。
  • 初始化零值、设置对象头、执行构造方法。

常见追问

  • 对象头里有什么?
  • TLAB 是什么?
  • 构造方法执行前对象是否已经有默认值?

一句话模板

对象创建不是只执行构造方法,而是先类加载检查,再内存分配,再默认初始化和对象头设置,最后执行构造逻辑。


对象一定分配在堆上吗?

面试官想看什么

  • 是否知道逃逸分析和标量替换。

核心答案

  • 从语言语义上看,对象是引用访问;从 JVM 优化看,如果对象没有逃逸,JIT 可能做标量替换或栈上相关优化。
  • 不能在业务代码里依赖“对象一定在栈上”这种实现细节。
  • 面试回答要强调:通常理解对象在堆上分配,但 HotSpot JIT 可能优化掉实际分配。

常见追问

  • 什么叫逃逸?
  • 逃逸分析有什么收益?

一句话模板

通常说对象在堆上,但 JIT 可能通过逃逸分析把没有逃逸的对象优化掉,所以面试要区分语义模型和实现优化。


类加载过程是什么?

面试官想看什么

  • 是否能说出加载、验证、准备、解析、初始化。

核心答案

  • 加载:获取类的二进制字节流,生成 Class 对象。
  • 验证:确保字节码符合 JVM 约束。
  • 准备:为类变量分配内存并设置默认初始值。
  • 解析:把符号引用替换为直接引用。
  • 初始化:执行类构造器 <clinit>,给静态变量赋程序设定值。

常见追问

  • 准备阶段和初始化阶段有什么区别?
  • 什么情况下触发类初始化?

一句话模板

类加载主线是加载、验证、准备、解析、初始化,其中准备阶段给默认值,初始化阶段才执行静态赋值和静态代码块。


什么是双亲委派模型?

面试官想看什么

  • 是否知道类加载器的委托链和安全意义。

核心答案

  • 类加载请求先向父加载器委托,父加载器无法完成时子加载器才尝试加载。
  • 这样可以避免核心类被随意替换,比如业务代码自定义 java.lang.String 不应覆盖 JDK 核心类。
  • 常见类加载器包括启动类加载器、平台类加载器、应用类加载器、自定义类加载器。

常见追问

  • 哪些场景会打破双亲委派?
  • SPI 为什么需要线程上下文类加载器?

一句话模板

双亲委派就是先让父加载器加载,父加载器不行再自己加载,核心价值是保证核心类库的稳定性和隔离性。


GC 与内存回收

如何判断对象可以被回收?

面试官想看什么

  • 是否能说清引用计数和可达性分析的区别。

核心答案

  • 主流 JVM 使用可达性分析,从 GC Roots 出发搜索引用链。
  • 不可达对象通常可被回收。
  • 常见 GC Roots 包括栈帧中的引用、静态字段引用、常量引用、JNI 引用、同步锁持有对象等。
  • 引用计数简单但难处理循环引用。

常见追问

  • 哪些对象可以作为 GC Roots?
  • finalize 是否推荐使用?

一句话模板

Java 主要靠可达性分析判断对象是否存活,从 GC Roots 能走到的对象存活,走不到的对象才可能被回收。


Java 引用类型有哪些?

面试官想看什么

  • 是否知道强、软、弱、虚引用适用场景。

核心答案

  • 强引用:普通对象引用,只要可达就不会被 GC。
  • 软引用:内存不足时更容易被回收,常用于缓存思路。
  • 弱引用:下一次 GC 时容易被回收,常见于弱引用 Map。
  • 虚引用:不能通过引用取对象,主要用于跟踪对象回收通知。

常见追问

  • WeakHashMap 适合什么场景?
  • 软引用缓存为什么现在不常作为主缓存方案?

一句话模板

引用强度从强到虚逐渐减弱,强引用保证存活,软弱虚更多用于缓存、映射和回收通知场景。


常见 GC 算法有哪些?

面试官想看什么

  • 是否理解标记清除、复制、标记整理的取舍。

核心答案

  • 标记清除:先标记存活对象,再清理垃圾;缺点是容易产生内存碎片。
  • 复制算法:把存活对象复制到另一块区域;适合存活对象少的区域。
  • 标记整理:标记后移动存活对象,减少碎片;移动成本更高。
  • 分代收集不是单一算法,而是基于对象生命周期特征组合算法。

常见追问

  • 为什么年轻代常用复制思路?
  • 老年代为什么更关注碎片?

一句话模板

GC 算法核心是在吞吐、停顿、碎片和移动成本之间取舍,分代收集就是把不同区域用不同策略组合起来。


新生代和老年代为什么要分代?

面试官想看什么

  • 是否理解大多数对象生命周期较短这一工程假设。

核心答案

  • 分代的核心是把生命周期不同的对象分开管理。
  • 年轻对象通常更快死亡,年轻代回收可以更频繁、更快。
  • 存活时间较长的对象晋升到老年代,老年代回收频率更低。
  • 分代能提高大多数业务场景下的回收效率,但不是所有收集器都以传统分代方式呈现。

常见追问

  • 对象如何晋升?
  • 大对象为什么可能直接进入老年代?

一句话模板

分代是为了利用对象生命周期差异:短命对象集中快速回收,长寿对象放到老年代降低扫描成本。


Minor GCMajor GCFull GC 怎么区分?

面试官想看什么

  • 是否知道这些名称在不同收集器和日志里可能不完全一致。

核心答案

  • Minor GC 通常指年轻代回收。
  • Major GC 常被用来指老年代回收,但不同资料和工具口径可能不同。
  • Full GC 通常指覆盖整个堆或多个内存区域的较重回收。
  • 面试中建议说清“以具体 GC 日志和收集器定义为准”。

常见追问

  • Full GC 频繁怎么办?
  • 为什么 Full GC 停顿更明显?

一句话模板

这些术语要结合收集器和日志口径看,通常年轻代回收叫 Minor GC,覆盖范围更大的整堆回收叫 Full GC。


常见垃圾收集器怎么选?

面试官想看什么

  • 是否能按业务目标选:吞吐、低延迟、资源成本。

核心答案

  • 吞吐优先:关注总处理能力,适合批处理、后台任务。
  • 延迟优先:关注停顿时间,适合接口服务、实时交互。
  • G1 面向服务端常见场景,目标是可预测停顿。
  • ZGC、Shenandoah 等更偏低延迟场景,但要结合 JDK 版本、部署环境和压测结果。

常见追问

  • G1 的 Region 是什么?
  • 为什么不能只凭经验改 GC?

一句话模板

GC 选择不是背名字,而是先看业务目标:吞吐优先还是低延迟优先,再用压测和 GC 日志验证。


G1 的核心思想是什么?

面试官想看什么

  • 是否知道 Region、停顿预测、混合回收。

核心答案

  • G1 把堆划分为多个 Region,不再只依赖连续的新生代和老年代空间。
  • 它会根据回收收益选择一批 Region 回收,目标是尽量满足停顿时间目标。
  • G1 仍然有年轻代回收,也会做混合回收。
  • G1 不是“不会 Full GC”,内存压力、晋升失败等仍可能触发更重的回收。

常见追问

  • Remembered Set 是什么?
  • Humongous Object 有什么风险?

一句话模板

G1 的关键是 Region 化和按收益回收,用可预测停顿作为目标,但它不是免 Full GC 的银弹。


线上频繁 Full GC 怎么排查?

面试官想看什么

  • 是否有真实排查路径,而不是只会改参数。

核心答案

  • 先看 GC 日志:触发原因、回收前后堆大小、停顿时间、老年代趋势。
  • 再看对象分布:dump 堆,找大对象、重复对象、异常增长集合。
  • 检查是否有内存泄漏:静态集合、缓存无淘汰、ThreadLocal 未清理、监听器未注销、类加载器泄漏。
  • 检查流量和分配速率:突增流量、批量任务、大响应对象、日志拼接。
  • 最后再调参数:堆大小、收集器、停顿目标、线程数等。

常见追问

  • dump 会不会影响线上?
  • 如何确认是泄漏还是正常高峰?

一句话模板

频繁 Full GC 先看日志定性,再用堆 dump 定位对象,再结合流量和代码找根因,最后才是参数调整。


OOM 常见类型和排查思路?

面试官想看什么

  • 是否能根据错误信息快速缩小范围。

核心答案

  • Java heap space:堆对象过多或泄漏。
  • Metaspace:类元数据过多,常见于动态生成类或类加载器泄漏。
  • Direct buffer memory:直接内存不足,常见于 NIO、Netty、文件传输。
  • unable to create native thread:线程过多或系统资源不足。
  • 排查要结合错误信息、dump、线程数、直接内存配置和系统限制。

常见追问

  • Netty 直接内存 OOM 怎么看?
  • 为什么线程过多会导致 OOM?

一句话模板

OOM 要先看具体错误类型,不同类型对应堆、元空间、直接内存、线程资源等不同方向。


JMM 与并发

Java 内存模型解决什么问题?

面试官想看什么

  • 是否能区分 JVM 内存区域和 JMM。

核心答案

  • JVM 运行时内存区域回答“数据放哪里”。
  • Java 内存模型回答“多线程读写共享变量时如何保证可见性、有序性和原子性语义”。
  • JMM 定义了 happens-before 等规则,用于判断线程间操作是否可见。

常见追问

  • 什么是 happens-before?
  • volatile 能保证什么?

一句话模板

JMM 不是堆栈划分,而是多线程共享变量的可见性和有序性规则。


volatile 的作用是什么?

面试官想看什么

  • 是否知道可见性、有序性,以及不保证复合操作原子性。

核心答案

  • 保证变量读写对线程可见。
  • 禁止相关指令重排序,常用于状态标记、双重检查锁定配合。
  • 不保证 i++ 这类复合操作的原子性。
  • 高频写场景下也要关注性能和设计是否合理。

常见追问

  • volatilesynchronized 区别?
  • 双重检查锁为什么需要 volatile

一句话模板

volatile 解决可见性和有序性,不解决复合操作原子性;需要互斥时还是要锁或原子类。


synchronized 的原理和优化?

面试官想看什么

  • 是否知道对象监视器、互斥、可见性、锁优化。

核心答案

  • synchronized 基于对象监视器实现互斥,进入和退出同步块会建立内存语义。
  • 可用于实例方法、静态方法、代码块。
  • HotSpot 有锁消除、锁粗化、轻量级锁等优化。
  • 偏向锁在新版本中已经不再是默认推荐关注点,面试要结合 JDK 版本说明。

常见追问

  • ReentrantLocksynchronized 怎么选?
  • 锁升级是什么?

一句话模板

synchronized 提供互斥和可见性,底层围绕对象监视器,现代 JVM 已经做了大量锁优化。


CAS 是什么?有什么问题?

面试官想看什么

  • 是否知道无锁更新的优势和 ABA、空转成本。

核心答案

  • CAS 是比较并交换,只有当前值等于预期值时才更新。
  • 优点是避免阻塞,适合竞争不严重的原子更新。
  • 问题包括 ABA、循环重试消耗 CPU、只能保证单变量或受限场景的一致性。
  • ABA 可通过版本号或带戳引用思路处理。

常见追问

  • 原子类底层怎么做?
  • 高竞争下 CAS 一定比锁好吗?

一句话模板

CAS 适合低到中等竞争的原子更新,高竞争下可能因为反复失败造成 CPU 浪费。


ThreadLocal 为什么可能内存泄漏?

面试官想看什么

  • 是否理解 ThreadLocalMap 和线程池场景。

核心答案

  • ThreadLocal 数据绑定在线程上,线程不结束,值就可能长期存在。
  • 在线程池中线程会复用,如果使用后不清理,旧值可能影响后续任务并导致内存占用。
  • 实践上应在 finally 中调用 remove

常见追问

  • ThreadLocalMap 的 key 和 value 引用关系?
  • 哪些框架大量使用 ThreadLocal?

一句话模板

ThreadLocal 的风险不在短生命周期线程,而在线程池复用;用完必须清理,尤其是用户上下文、事务上下文这类对象。


性能排查

CPU 飙高如何排查 JVM 问题?

面试官想看什么

  • 是否会从系统线程定位到 Java 线程栈。

核心答案

  • 找到高 CPU 进程。
  • 找到进程内高 CPU 线程。
  • 把系统线程 ID 转成线程 dump 中可匹配的格式。
  • jstackjcmd Thread.print 看线程栈,定位热点代码、死循环、锁竞争或 GC 线程。
  • 结合日志和监控确认是否流量突增、死循环、序列化、正则、加密压缩等热点。

常见追问

  • 如何判断是业务线程还是 GC 线程?
  • 线程 dump 要打几次?

一句话模板

CPU 高要从进程到线程再到 Java 栈,最终落到具体方法和调用路径,而不是上来就调 JVM 参数。


接口 RT 突然变高怎么从 JVM 角度排查?

面试官想看什么

  • 是否会把 GC、锁、线程池、外部依赖联系起来。

核心答案

  • 先看是否有 GC 停顿,尤其是 Full GC 或长时间年轻代 GC。
  • 看线程池是否打满、队列是否积压。
  • 看锁竞争和阻塞线程。
  • 看下游依赖慢导致线程堆积。
  • 看对象分配速率和大对象创建是否异常。

常见追问

  • GC 停顿和接口 RT 如何关联?
  • 如何判断是 JVM 内部问题还是下游问题?

一句话模板

RT 变高要同时看 GC、线程、锁和下游,JVM 只是其中一层,关键是用时间线把现象串起来。


常用 JVM 排查工具有哪些?

面试官想看什么

  • 是否会用工具,不只会概念。

核心答案

  • jps:看 Java 进程。
  • jstat:看 GC 和类加载等统计。
  • jmap:看堆信息或生成 dump。
  • jstack:看线程栈。
  • jcmd:综合诊断命令,很多场景可替代多种老工具。
  • MAT、JFR、VisualVM、async-profiler 常用于更深入分析。

常见追问

  • 线上 dump 风险是什么?
  • JFR 适合什么场景?

一句话模板

基础排查用 jstat 看趋势、jstack 看线程、dump 看对象;更完整的诊断可以用 jcmd、JFR 和 profiler。


JVM 参数调优怎么答?

面试官想看什么

  • 是否知道调优是验证过程,不是背参数。

核心答案

  • 明确目标:吞吐、延迟、内存占用、启动速度。
  • 建立基线:流量模型、RT、错误率、GC 日志、CPU、内存。
  • 单变量调整:每次只改关键参数,压测验证。
  • 关注副作用:堆变大可能降低 GC 频率,但单次停顿可能更长。
  • 保留回滚方案。

常见追问

  • 堆越大越好吗?
  • -Xms-Xmx 怎么设?

一句话模板

JVM 调优不是套模板,而是目标、基线、实验、验证、回滚的工程过程。


加分题

什么是安全点 Safepoint?

核心答案

  • JVM 某些操作需要所有线程到达可安全暂停的位置,例如部分 GC、反优化、栈遍历。
  • 如果线程长时间不到安全点,可能影响 Stop-The-World 操作。

一句话模板

Safepoint 是 JVM 能安全暂停线程的位置,很多全局操作要等线程到达安全点才能进行。


JIT 编译有什么作用?

核心答案

  • Java 代码先以字节码形式运行,热点代码可被即时编译器优化为机器码。
  • 常见优化包括方法内联、逃逸分析、锁消除、公共子表达式消除等。
  • JIT 提升长期运行性能,但也带来预热成本。

一句话模板

JIT 的核心是把热点路径编译优化,让 Java 在长期运行时获得更好性能。


String 常量池怎么答?

核心答案

  • 字符串字面量会进入字符串常量池。
  • intern 会尝试返回池中的规范化字符串引用。
  • 面试中要避免背死不同 JDK 的实现细节,重点讲清常量池复用和引用比较风险。

一句话模板

String 常量池用于复用字符串字面量,但业务中比较内容应使用 equals,不要依赖引用相等。


面试最后可反问

  • 你们线上主要用哪种 GC?有固定的 GC 日志采集和告警规范吗?
  • 服务对延迟还是吞吐更敏感?
  • 生产排查时是否允许 dump?有没有脱敏和隔离环境?
  • 是否使用 JFR 或 APM 做持续性能画像?

来源与出处


信心指数

信心指数:8/10。
低于满分原因:不同公司对“高频”的排序没有统一公开统计来源;本文按 Java 后端常见面试覆盖面整理,已在开头标注“暂无来源可查”。