JVM面试题高频TOP榜单
基于第1-13章面试题总结,按照面试出现频率整理的最高频面试题
🏆 最高频面试题 TOP 20
TOP 1: JVM内存区域划分(⭐⭐⭐⭐⭐ 超高频)
问题:JVM内存区域有哪些?哪些是线程私有的,哪些是线程共享的?
答案要点:
┌─────────────────────────────────────────────────────────┐
│ JVM 运行时数据区 │
├─────────────────────────────────────────────────────────┤
│ 线程共享区域 │
│ ├── 堆(Heap):存放对象实例 │
│ └── 方法区(Method Area):类信息、常量、静态变量 │
├─────────────────────────────────────────────────────────┤
│ 线程私有区域 │
│ ├── 程序计数器(PC Register) │
│ ├── 虚拟机栈(VM Stack) │
│ └── 本地方法栈(Native Method Stack) │
└─────────────────────────────────────────────────────────┘面试延伸:
- 程序计数器为什么不会发生OOM?
- 虚拟机栈和本地方法栈的区别?
- 堆为什么要分代?
TOP 2: 垃圾回收算法(⭐⭐⭐⭐⭐ 超高频)
问题:常见的垃圾收集算法有哪些?各自的优缺点?
答案要点:
| 算法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 标记-清除 | 实现简单,不需要移动对象 | 效率低,产生内存碎片 | 老年代(CMS) |
| 复制 | 效率高,无内存碎片 | 内存利用率低(50%) | 新生代 |
| 标记-整理 | 无内存碎片 | 需要移动对象,停顿时间长 | 老年代 |
| 分代收集 | 针对不同代采用不同算法 | 实现复杂 | 现代JVM标准方案 |
面试延伸:
- 为什么新生代用复制算法,老年代用标记-整理?
- Eden和Survivor的比例为什么是8:1:1?
TOP 3: 垃圾收集器对比(⭐⭐⭐⭐⭐ 超高频)
问题:CMS和G1收集器有什么区别?
答案要点:
| 特性 | CMS | G1 |
|---|---|---|
| 算法 | 标记-清除 | 标记-整理 + 复制 |
| 内存碎片 | 有 | 无 |
| 停顿时间 | 不可预测 | 可预测(MaxGCPauseMillis) |
| 内存布局 | 传统分代 | 分区(Region) |
| 适用堆大小 | 中小型堆 | 大堆(6GB+) |
| Full GC | 单线程Serial Old | 多线程并行 |
面试延伸:
- CMS的四个阶段是什么?
- 什么是Concurrent Mode Failure?
- G1的Mixed GC是什么?
TOP 4: synchronized底层原理(⭐⭐⭐⭐⭐ 超高频)
问题:synchronized的底层原理是什么?
答案要点:
字节码层面:
- 同步代码块:
monitorenter和monitorexit指令 - 同步方法:
ACC_SYNCHRONIZED访问标志
对象头(Mark Word):
| 锁状态 | 25bit | 4bit | 1bit(偏向锁位) | 2bit(锁标志位) |
|----------|----------------|----------|----------------|----------------|
| 无锁 | 对象HashCode | 分代年龄 | 0 | 01 |
| 偏向锁 | 线程ID|Epoch | 分代年龄 | 1 | 01 |
| 轻量级锁 | 指向栈中锁记录指针 | - | - | 00 |
| 重量级锁 | 指向互斥量指针 | - | - | 10 |面试延伸:
- 锁升级过程是怎样的?
- 为什么JDK 15后要禁用偏向锁?
TOP 5: volatile关键字(⭐⭐⭐⭐⭐ 超高频)
问题:volatile关键字的作用是什么?能保证原子性吗?
答案要点:
两个核心作用:
- 保证可见性:写volatile立即刷新到主内存,读volatile直接从主内存读取
- 保证有序性:禁止指令重排序
不能保证原子性:
private volatile int count = 0;
public void increment() {
count++; // 不是原子操作!包含读-改-写三个步骤
}使用场景:
- 状态标志位
- 双重检查锁定(DCL)单例模式
- 读多写少的场景
面试延伸:
- DCL单例模式为什么要用volatile?
- volatile的内存屏障是什么?
TOP 6: 锁升级过程(⭐⭐⭐⭐⭐ 超高频)
问题:讲一讲Java的锁升级过程?
答案要点:
锁升级路径:
无锁 → 偏向锁 → 轻量级锁 → 重量级锁| 阶段 | 触发条件 | 特点 |
|---|---|---|
| 无锁 | 初始状态 | 对象刚创建 |
| 偏向锁 | 只有一个线程访问 | 记录线程ID,无CAS |
| 轻量级锁 | 多个线程交替访问 | CAS获取锁,自旋等待 |
| 重量级锁 | 多个线程同时竞争 | 操作系统Mutex,线程阻塞 |
面试延伸:
- 什么是自旋锁?
- 锁消除和锁粗化是什么?
TOP 7: Java内存模型JMM(⭐⭐⭐⭐⭐ 超高频)
问题:什么是Java内存模型(JMM)?主内存和工作内存的关系是什么?
答案要点:
JMM定义:Java虚拟机规范中定义的内存访问规则,规范多线程环境下共享变量的访问方式。
三大特性:
- 可见性:一个线程对共享变量的修改,其他线程能否立即看到
- 原子性:一个或多个操作要么全部执行,要么完全不执行
- 有序性:程序执行的顺序是否按照代码的先后顺序
主内存和工作内存:
- 主内存:所有线程共享,存储共享变量
- 工作内存:每个线程私有,存储主内存变量的副本
面试延伸:
- happens-before原则是什么?
- 有哪些happens-before规则?
TOP 8: 类加载机制(⭐⭐⭐⭐⭐ 超高频)
问题:类的加载过程是什么?双亲委派模型是什么?
答案要点:
类加载过程:
加载 → 验证 → 准备 → 解析 → 初始化双亲委派模型:
自定义类加载器
↑
应用程序类加载器(AppClassLoader)
↑
扩展类加载器(ExtensionClassLoader)
↑
启动类加载器(BootstrapClassLoader)工作流程:
- 收到类加载请求
- 委托给父类加载器
- 父类加载器无法加载,子类加载器才尝试加载
面试延伸:
- 为什么要用双亲委派模型?
- 如何打破双亲委派模型?
- Tomcat的类加载机制是怎样的?
TOP 9: 线程安全的实现方式(⭐⭐⭐⭐⭐ 超高频)
问题:Java中如何保证线程安全?有哪些实现方式?
答案要点:
三种实现方式:
| 方式 | 实现 | 特点 |
|---|---|---|
| 互斥同步 | synchronized、ReentrantLock | 阻塞,性能较低 |
| 非阻塞同步 | CAS、Atomic类 | 无阻塞,轻量级 |
| 无同步方案 | 不可变对象、ThreadLocal | 无需同步,性能最好 |
面试延伸:
- synchronized和ReentrantLock的区别?
- 什么是CAS?有什么优缺点?
- ThreadLocal的原理是什么?
TOP 10: OOM和StackOverflowError(⭐⭐⭐⭐⭐ 超高频)
问题:Java中常见的内存溢出有哪些?如何解决?
答案要点:
| 异常类型 | 发生区域 | 原因 | 解决方案 |
|---|---|---|---|
| OutOfMemoryError: Java heap space | 堆 | 对象过多,内存不足 | 增大堆内存、检查内存泄漏 |
| OutOfMemoryError: Metaspace | 方法区 | 类加载过多 | 增大Metaspace、检查动态代理 |
| OutOfMemoryError: GC overhead limit exceeded | 堆 | GC效率过低 | 增大堆内存、优化代码 |
| StackOverflowError | 栈 | 递归过深、栈帧过多 | 优化递归、增大栈内存 |
面试延伸:
- 如何排查内存泄漏?
- 常用的JVM调优参数有哪些?
TOP 11: 引用类型(⭐⭐⭐⭐ 高频)
问题:Java中有哪几种引用类型?它们的区别是什么?
答案要点:
| 引用类型 | 回收时机 | 使用场景 | get()方法 |
|---|---|---|---|
| 强引用 | 永不回收 | 普通对象引用 | 返回对象 |
| 软引用 | 内存不足时回收 | 缓存实现 | 返回对象 |
| 弱引用 | 下次GC时回收 | WeakHashMap | 返回对象 |
| 虚引用 | 随时可能回收 | 跟踪对象回收状态 | 永远返回null |
面试延伸:
- 软引用和弱引用的区别?
- ReferenceQueue的作用是什么?
TOP 12: 对象创建和内存分配(⭐⭐⭐⭐ 高频)
问题:对象创建的过程是什么?内存分配策略有哪些?
答案要点:
对象创建过程:
类加载检查 → 分配内存 → 初始化零值 → 设置对象头 → 执行构造方法内存分配策略:
- 指针碰撞:内存规整时使用
- 空闲列表:内存不规整时使用
- TLAB:线程本地分配缓冲区,避免线程竞争
面试延伸:
- 对象在内存中的布局是怎样的?
- 什么是逃逸分析?
TOP 13: 逃逸分析(⭐⭐⭐⭐ 高频)
问题:什么是逃逸分析?有什么优化手段?
答案要点:
逃逸分析:分析对象动态作用域,判断对象是否逃逸出方法或线程。
三种逃逸状态:
- 不逃逸:对象只在方法内部使用
- 方法逃逸:对象被外部方法引用
- 线程逃逸:对象被其他线程引用
优化手段:
| 优化 | 说明 |
|---|---|
| 栈上分配 | 不逃逸的对象在栈上分配,随栈帧销毁 |
| 标量替换 | 将对象拆分为基本类型分配在栈上 |
| 同步消除 | 不逃逸的对象无需同步 |
面试延伸:
- 逃逸分析有什么局限性?
- 如何开启逃逸分析?
TOP 14: JIT编译器(⭐⭐⭐⭐ 高频)
问题:什么是JIT编译器?热点代码检测是什么?
答案要点:
JIT(Just In Time):即时编译器,将热点字节码编译为本地机器码。
分层编译:
| 层级 | 编译器 | 特点 |
|---|---|---|
| 0 | 解释器 | 启动快,执行慢 |
| 1-3 | C1编译器 | 简单优化,快速编译 |
| 4 | C2编译器 | 激进优化,编译慢执行快 |
热点代码检测:
- 方法调用计数器:统计方法调用次数
- 回边计数器:统计循环执行次数
- 阈值:Client模式1500次,Server模式10000次
面试延伸:
- C1和C2编译器的区别?
- 什么是方法内联?
TOP 15: Full GC触发条件(⭐⭐⭐⭐ 高频)
问题:什么时候会触发Full GC?
答案要点:
触发条件:
- 老年代空间不足:Minor GC后晋升对象过多
- Metaspace空间不足:类加载过多
- System.gc()调用:建议JVM进行Full GC
- CMS的Concurrent Mode Failure:并发清理时老年代空间不足
- G1的Evacuation Failure:复制存活对象时空间不足
面试延伸:
- 如何减少Full GC的频率?
- Full GC和Minor GC的区别?
TOP 16: 类加载器(⭐⭐⭐⭐ 高频)
问题:Java中有哪些类加载器?
答案要点:
| 类加载器 | 加载路径 | 说明 |
|---|---|---|
| 启动类加载器 | <JAVA_HOME>/lib | C++实现,加载核心类 |
| 扩展类加载器 | <JAVA_HOME>/lib/ext | Java实现,加载扩展类 |
| 应用程序类加载器 | classpath | 加载应用程序类 |
| 自定义类加载器 | 自定义路径 | 继承ClassLoader |
面试延伸:
- 如何自定义类加载器?
- 类加载器的命名空间是什么?
TOP 17: 内存分配与回收策略(⭐⭐⭐⭐ 高频)
问题:对象优先在Eden区分配吗?大对象如何处理?
答案要点:
对象分配策略:
- 优先Eden区:大多数对象在Eden区分配
- 大对象直接进入老年代:
-XX:PretenureSizeThreshold - 长期存活对象进入老年代:默认15岁(
-XX:MaxTenuringThreshold) - 动态对象年龄判定:Survivor区相同年龄对象大小超过一半,大于等于该年龄的对象直接进入老年代
空间分配担保:
- Minor GC前检查老年代最大可用连续空间是否大于新生代所有对象总空间
- 不足则检查是否允许担保失败
- 允许则检查老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小
TOP 18: 线程池(⭐⭐⭐⭐ 高频)
问题:线程池的核心参数有哪些?拒绝策略有哪些?
答案要点:
核心参数:
| 参数 | 说明 |
|---|---|
| corePoolSize | 核心线程数 |
| maximumPoolSize | 最大线程数 |
| keepAliveTime | 非核心线程存活时间 |
| workQueue | 任务等待队列 |
| threadFactory | 线程工厂 |
| handler | 拒绝策略 |
拒绝策略:
| 策略 | 说明 |
|---|---|
| AbortPolicy | 直接抛出异常(默认) |
| CallerRunsPolicy | 由调用线程执行任务 |
| DiscardPolicy | 静默丢弃任务 |
| DiscardOldestPolicy | 丢弃队列最老的任务 |
TOP 19: happens-before原则(⭐⭐⭐⭐ 高频)
问题:什么是happens-before原则?有哪些规则?
答案要点:
定义:如果A happens-before B,则A的操作结果对B可见。
八大规则:
- 程序次序规则:同一线程内,按代码顺序执行
- 锁规则:unlock happens-before 后续的lock
- volatile规则:volatile写 happens-before 后续的读
- 传递性:A→B,B→C,则A→C
- start规则:Thread.start() happens-before 线程内所有操作
- join规则:线程内所有操作 happens-before Thread.join()返回
- 中断规则:interrupt() happens-before 检测到中断
- finalize规则:对象构造 happens-before finalize()
TOP 20: JVM调优参数(⭐⭐⭐⭐ 高频)
问题:常用的JVM调优参数有哪些?
答案要点:
堆内存参数:
-Xms512m # 堆初始大小
-Xmx2g # 堆最大大小
-Xmn256m # 新生代大小
-XX:NewRatio=2 # 老年代/新生代比例
-XX:SurvivorRatio=8 # Eden/Survivor比例垃圾收集器参数:
-XX:+UseG1GC # 使用G1收集器
-XX:MaxGCPauseMillis=200 # 最大GC停顿时间
-XX:+UseConcMarkSweepGC # 使用CMS收集器
-XX:CMSInitiatingOccupancyFraction=68 # CMS触发阈值监控参数:
-XX:+PrintGCDetails # 打印GC详情
-XX:+PrintGCDateStamps # 打印GC时间戳
-Xloggc:/path/to/gc.log # GC日志文件📊 高频面试题分类统计
按章节分布
| 章节 | 高频题数量 | 占比 |
|---|---|---|
| 第2章 内存区域 | 3 | 15% |
| 第3章 垃圾回收 | 5 | 25% |
| 第7章 类加载 | 2 | 10% |
| 第11章 运行时优化 | 1 | 5% |
| 第12章 JMM | 4 | 20% |
| 第13章 线程安全 | 5 | 25% |
按类型分布
| 类型 | 数量 | 占比 |
|---|---|---|
| 基础概念 | 6 | 30% |
| 原理机制 | 8 | 40% |
| 对比分析 | 4 | 20% |
| 实战调优 | 2 | 10% |
💡 面试技巧
回答结构建议
- 概念定义:先给出清晰的定义
- 原理讲解:解释底层实现机制
- 对比分析:与其他技术对比(如有)
- 使用场景:说明适用场景
- 延伸扩展:提及相关知识点
高频考点组合
组合1:JVM内存 + GC算法 + 垃圾收集器
- 必考组合,建议连贯掌握
组合2:synchronized + volatile + JMM
- 并发编程核心,几乎必考
组合3:类加载 + 双亲委派 + 打破机制
- 框架设计基础,高级面试常考
📚 推荐阅读顺序
- 基础篇:JVM内存区域 → 垃圾回收算法 → 垃圾收集器
- 并发篇:JMM → volatile → synchronized → 锁优化
- 进阶篇:类加载 → JIT编译 → 逃逸分析 → JVM调优
文档生成时间:2026-03-29
数据来源:第1-13章面试题总结
统计范围:约200+道面试题