Skip to content

JVM 速查卡

🎯 覆盖 23 题 | ⭐ 高频 8 题 | 预计扫描 10 分钟 📌 先看⭐一句话答案 → 展开要点 → 自测清单检验


一、内存结构

知识地图:堆(对象) + 方法区/Metaspace(类信息) = 共享 | 栈+本地方法栈+PC = 私有

⭐ JVM 内存结构

一句话: JVM 运行时数据区分为线程共享(堆、方法区)和线程私有(虚拟机栈、本地方法栈、程序计数器)五大区域。

线程共享:堆(Eden|S0|S1|老年代)     ← GC 主战场,new 的对象都在这
         方法区/Metaspace(类信息|常量池|静态变量) ← JDK8 移到本地内存
线程私有:虚拟机栈(栈帧=局部变量表+操作数栈)
         本地方法栈(native 方法)
         程序计数器 ← 唯一不会 OOM 的区域

堆的分代: 年轻代(1/3) = Eden(8) + S0(1) + S1(1) | 老年代(2/3)

晋升老年代的条件:

  1. 年龄达 15(MaxTenuringThreshold)
  2. 动态年龄判断(同龄对象总大小 > Survivor 50%)
  3. 大对象直接进老年代
  4. Survivor 放不下(空间担保)

⚠️ 易错:JDK 8 方法区改为 Metaspace,使用本地内存(不受 -Xmx 限制)


⭐ OOM 排查

一句话: 配置 -XX:+HeapDumpOnOutOfMemoryError 自动 dump → MAT 分析 Retained Heap → 定位泄漏对象的 GC Root 引用链。

区域OOM 错误常见原因
Java heap space内存泄漏/对象过多/堆太小
MetaspaceMetaspace动态生成大量类(CGLIB)
StackOverflowError无限递归
程序计数器不会 OOM

CPU 100% 排查四步法: top(找进程) → top -Hp(找线程) → 转16进制 → jstack(搜 nid 定位代码)


二、垃圾回收

知识地图:标记清除(碎片) / 标记复制(空间浪费) / 标记整理(移动慢) → CMS vs G1 vs ZGC

⭐ GC 算法三兄弟

一句话: 三种基础算法——标记清除(有碎片)、标记复制(浪费空间但无碎片,年轻代用)、标记整理(无碎片但移动对象慢,老年代用)。

算法优点缺点用在
标记-清除简单内存碎片CMS 老年代
标记-复制无碎片,分配快空间利用率50%(改进版Eden:S0:S1=8:1:1)年轻代
标记-整理无碎片,利用率高移动对象要更新引用(STW长)G1 老年代

⭐ GC 触发条件 + Full GC 表现

一句话: Minor GC = Eden 满;Full GC = 老年代不足/担保失败/Metaspace不足/System.gc(),期间 STW 导致接口超时。

Full GC 五大触发条件: 老年代空间不足 | System.gc() | 空间担保失败 | Metaspace 不足 | CMS Concurrent Mode Failure

减少 Full GC: 减少大对象 + 增大年轻代 + 升级 G1/ZGC + 分析 GC 日志找泄漏


⭐ CMS vs G1

一句话: CMS 追求最短 STW(标记清除,有碎片),G1 追求可预测停顿(Region 化 + 标记整理,无碎片);JDK 9+ 默认 G1。

维度CMSG1
算法标记-清除(有碎片)整体标记-整理(无碎片)
作用范围仅老年代整个堆(Region)
停顿控制不可预测-XX:MaxGCPauseMillis(默认200ms)
适合堆 < 6GB堆 ≥ 6GB
版本建议JDK ≤ 8JDK ≥ 9(默认)

CMS 四阶段: 初始标记(STW) → 并发标记 → 重新标记(STW) → 并发清除

G1 核心: 堆切为等大 Region(1-32MB),每个 Region 动态扮演 Eden/Survivor/Old/Humongous;优先回收垃圾最多的 Region(Garbage First)

ZGC: 停顿 < 10ms 且与堆大小无关;核心技术 = 染色指针 + 读屏障

⚠️ 易错:CMS 的致命缺陷是碎片积累导致 Concurrent Mode Failure,退化为 Serial Old 全停顿


三、类加载

⭐ 类加载五阶段 + 双亲委派

一句话: 加载 → 验证 → 准备(static 赋零值) → 解析(符号→直接引用) → 初始化(执行 clinit);双亲委派从子到父委托加载,保证核心类不被篡改。

Bootstrap(rt.jar) ← Extension(lib/ext) ← Application(classpath) ← 自定义
收到请求 → 先委托父加载器 → 父找不到 → 子自己加载

打破双亲委派: ① 自定义 ClassLoader 重写 loadClass()(Tomcat 热部署) ② SPI 线程上下文类加载器(JDBC) ③ OSGi 网状加载

⚠️ 易错:准备阶段 static int x = 10 赋零值 0,初始化阶段才赋真实值 10;但 static final 在准备阶段就赋真实值


补充速览

关键词核心答案
判断垃圾可达性分析(从 GC Root 出发);引用计数有循环引用问题,Java 不用
GC Root栈帧局部变量、static 变量、JNI 引用、活跃线程、synchronized 持有对象
内存泄漏 vs 溢出泄漏 = 对象不再用但 GC 无法回收(仍被引用);泄漏积累导致溢出
常见泄漏静态 Map 只进不出 / ThreadLocal 未 remove / 未关闭连接
new 对象流程类检查加载 → 分配内存(指针碰撞/空闲列表+TLAB) → 零值初始化 → 设对象头(Mark Word+Klass) → 执行构造
虚拟线程(JVM角度)JVM 调度的轻量线程,M:N 映射 OS 线程;IO 阻塞自动卸载 carrier thread
⭐ JIT 编译热点代码(方法调用>10000次)编译为机器码;C1(快编译,轻优化)→C2(慢编译,深优化)分层编译
逆优化JIT 激进优化的假设被打破(如新类加载)→退回解释执行→重新编译
⭐ 逃逸分析分析对象是否逃出方法/线程;不逃逸→标量替换(拆散为局部变量)/锁消除
对象不一定在堆上HotSpot 通过标量替换间接实现"栈上分配"效果;-XX:+DoEscapeAnalysis 默认开启

🧠 助记汇总

口诀含义
加验准解初类加载五阶段
清复整GC 三算法:标记清除/标记复制/标记整理
栈类JNI线锁GC Root 五种来源
E区满Minor,老区满FullGC 触发条件简记

✅ 自测清单

#问题你能说出...
1JVM 内存结构五大区域 + 各存什么 + 哪些共享哪些私有
2堆分代比例 + 晋升老年代的 4 种情况
3GC 算法三种算法优缺点 + 分别用在哪
4CMS vs G1核心区别表 + 各自适用场景
5Full GC 触发5 种触发条件 + 系统表现
6JIT 分层编译C1/C2 区别 + 热点探测机制
7逃逸分析三种优化(标量替换/锁消除/栈上分配) + "对象一定在堆上吗"
6类加载五阶段 + 双亲委派流程 + 3 种打破场景
7OOM 排查HeapDump + MAT 分析链路
8CPU 100% 排查四步法

💡 首次全部过一遍 → 第2天只过答不上来的 → 第4天再复习 → 面试前一天最后扫一遍