基于:JDK 8 / HotSpot VM(2014-03 发布,LTS 长期支持版本);平台 Windows / macOS / Linux
本文是 Java 8 JVM 的知识地图:以「五大功能域」(内存结构、类加载、执行引擎、GC、调优工具)为主线,梳理每个域解决什么问题、核心组件是什么、彼此如何协同,并给出学习路线。适合系统学习 JVM、面试突击、或排查线上问题前先建立全局观。
目录
- [定位:为什么学 Java 还要学 JVM](#定位:为什么学 Java 还要学 JVM)
- [核心脉络总表:问题 → 解法 → 组件](#核心脉络总表:问题 → 解法 → 组件)
- 全景关系图
- [功能域一:运行时数据区与 JMM 内存模型](#功能域一:运行时数据区与 JMM 内存模型)
- 功能域二:类加载机制
- 功能域三:字节码与执行引擎
- [功能域四:垃圾回收 GC](#功能域四:垃圾回收 GC)
- [功能域五:JVM 参数、监控与排查工具](#功能域五:JVM 参数、监控与排查工具)
- [版本演进:JVM 简史与 Java 8 的关键变化](#版本演进:JVM 简史与 Java 8 的关键变化)
- 学习路线图
- 总结
1. 定位:为什么学 Java 还要学 JVM
1.1 JVM 是什么
- JVM(Java Virtual Machine) 是运行 Java 字节码的虚拟机,屏蔽操作系统与硬件差异,实现"一次编写,到处运行"。
- Java 语言与 JVM 是解耦的:Kotlin、Scala、Groovy 同样编译为字节码运行在 JVM 上。
| 概念 | 定位 | 包含内容 |
|---|---|---|
| JDK | 开发工具包 | 编译器 javac、JVM、核心类库、jps/jstat 等工具 |
| JRE | 运行环境 | JVM + 核心类库(Java 11 起不再单独发布 JRE) |
| JVM | 虚拟机 | 类加载子系统、运行时数据区、执行引擎、GC |
1.2 为什么要学 JVM
- 性能调优:吞吐量/响应时间不达标时,需要依据 GC 日志、堆快照定位瓶颈;
- 故障排查:OOM、CPU 100%、内存泄漏、死锁等线上问题,最终都要落到 JVM 层面分析;
- 并发正确性:理解 JMM(Java 内存模型)才能写出正确的 volatile、锁、并发容器代码;
- 面试:JVM 是 Java 后端面试的必考模块。
1.3 为什么以 Java 8 为基准
- LTS 版本:企业存量系统绝大多数运行在 JDK 8,生产环境排查绕不开;
- 关键变革节点:永久代移除 → 元空间(Metaspace)、Lambda(invokedynamic)、默认并行回收器、分层编译默认开启,Java 8 是承上启下的分水岭。
关键认知 :JVM 学习应区分规范 (JVM Spec,各厂商通用)与实现(HotSpot,Oracle JDK / OpenJDK 的默认实现)。绝大多数"调优参数、GC 收集器"都是 HotSpot 实现层面的内容,读资料时先分清讨论的是哪一层。
2. 核心脉络总表:问题 → 解法 → 组件
JVM 的每个功能域都源于一个真实问题,先看总表再深入细节:
| 要解决的问题 | 解法 | 核心组件 / 机制 | 对应功能域 |
|---|---|---|---|
| 程序运行时数据放哪、为什么会 OOM/栈溢出 | 定义运行时数据区并做内存管理 | 堆、虚拟机栈、方法区(元空间)、直接内存 | 域一 内存结构 |
| 多线程下共享变量的可见性/有序性 | 定义内存模型,规范主内存与工作内存交互 | JMM、volatile、happens-before | 域一 JMM |
| .class 文件何时、如何变成内存中的 Class | 类生命周期管理 + 双亲委派 | 类加载器、双亲委派模型、SPI 打破 | 域二 类加载 |
| 字节码如何被执行、如何变快 | 解释执行 + 即时编译 | 解释器、C1/C2 编译器、分层编译、栈帧 | 域三 执行引擎 |
| 堆里的垃圾对象何时回收、如何不"卡" | 可达性分析 + 分代收集 + 收集器算法 | GC Roots、新生代/老年代、CMS/G1 | 域四 GC |
| 线上如何观测与排查 | 提供参数开关与命令行工具 | -Xmx 等参数、jps/jstat/jmap/jstack/MAT | 域五 工具 |
3. 全景关系图
#mermaid-svg-ktP04eYnyFIdH2fw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ktP04eYnyFIdH2fw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ktP04eYnyFIdH2fw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ktP04eYnyFIdH2fw .error-icon{fill:#552222;}#mermaid-svg-ktP04eYnyFIdH2fw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ktP04eYnyFIdH2fw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ktP04eYnyFIdH2fw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ktP04eYnyFIdH2fw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ktP04eYnyFIdH2fw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ktP04eYnyFIdH2fw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ktP04eYnyFIdH2fw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ktP04eYnyFIdH2fw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ktP04eYnyFIdH2fw .marker.cross{stroke:#333333;}#mermaid-svg-ktP04eYnyFIdH2fw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ktP04eYnyFIdH2fw p{margin:0;}#mermaid-svg-ktP04eYnyFIdH2fw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ktP04eYnyFIdH2fw .cluster-label text{fill:#333;}#mermaid-svg-ktP04eYnyFIdH2fw .cluster-label span{color:#333;}#mermaid-svg-ktP04eYnyFIdH2fw .cluster-label span p{background-color:transparent;}#mermaid-svg-ktP04eYnyFIdH2fw .label text,#mermaid-svg-ktP04eYnyFIdH2fw span{fill:#333;color:#333;}#mermaid-svg-ktP04eYnyFIdH2fw .node rect,#mermaid-svg-ktP04eYnyFIdH2fw .node circle,#mermaid-svg-ktP04eYnyFIdH2fw .node ellipse,#mermaid-svg-ktP04eYnyFIdH2fw .node polygon,#mermaid-svg-ktP04eYnyFIdH2fw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ktP04eYnyFIdH2fw .rough-node .label text,#mermaid-svg-ktP04eYnyFIdH2fw .node .label text,#mermaid-svg-ktP04eYnyFIdH2fw .image-shape .label,#mermaid-svg-ktP04eYnyFIdH2fw .icon-shape .label{text-anchor:middle;}#mermaid-svg-ktP04eYnyFIdH2fw .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ktP04eYnyFIdH2fw .rough-node .label,#mermaid-svg-ktP04eYnyFIdH2fw .node .label,#mermaid-svg-ktP04eYnyFIdH2fw .image-shape .label,#mermaid-svg-ktP04eYnyFIdH2fw .icon-shape .label{text-align:center;}#mermaid-svg-ktP04eYnyFIdH2fw .node.clickable{cursor:pointer;}#mermaid-svg-ktP04eYnyFIdH2fw .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ktP04eYnyFIdH2fw .arrowheadPath{fill:#333333;}#mermaid-svg-ktP04eYnyFIdH2fw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ktP04eYnyFIdH2fw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ktP04eYnyFIdH2fw .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ktP04eYnyFIdH2fw .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ktP04eYnyFIdH2fw .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ktP04eYnyFIdH2fw .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ktP04eYnyFIdH2fw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ktP04eYnyFIdH2fw .cluster text{fill:#333;}#mermaid-svg-ktP04eYnyFIdH2fw .cluster span{color:#333;}#mermaid-svg-ktP04eYnyFIdH2fw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ktP04eYnyFIdH2fw .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ktP04eYnyFIdH2fw rect.text{fill:none;stroke-width:0;}#mermaid-svg-ktP04eYnyFIdH2fw .icon-shape,#mermaid-svg-ktP04eYnyFIdH2fw .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ktP04eYnyFIdH2fw .icon-shape p,#mermaid-svg-ktP04eYnyFIdH2fw .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ktP04eYnyFIdH2fw .icon-shape .label rect,#mermaid-svg-ktP04eYnyFIdH2fw .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ktP04eYnyFIdH2fw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ktP04eYnyFIdH2fw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ktP04eYnyFIdH2fw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} JVM
编译期
javac 编译
读取字节码 / 操作数据
JNI
Java 源码 .java
字节码 .class
类加载子系统
加载/验证/准备/解析/初始化
运行时数据区
堆 / 栈 / 元空间 / 直接内存
执行引擎
解释器 + JIT 编译器
垃圾回收器
作用于堆与方法区
本地方法库
C/C++ 库
- 类加载子系统负责把字节码装进内存;执行引擎负责跑起来;GC 负责回收堆里没用的对象。
- JMM 描述的是"多线程与运行时数据区(主内存/工作内存)如何交互"的规则层。
一句话概括:字节码是原料,类加载是进货,运行时数据区是仓库,执行引擎是工人,GC 是清仓,调优工具是摄像头。
4. 功能域一:运行时数据区与 JMM 内存模型 ★★★
4.1 运行时数据区总览
| 区域 | 线程私有/共享 | 存储内容 | 异常 |
|---|---|---|---|
| 程序计数器 | 私有 | 当前线程执行字节码的行号 | 唯一无异常区域 |
| 虚拟机栈 | 私有 | 栈帧(局部变量表、操作数栈...) | StackOverflowError |
| 本地方法栈 | 私有 | native 方法调用 | StackOverflowError |
| 堆 | 共享 | 对象实例、数组 | OutOfMemoryError |
| 方法区(Java 8:元空间) | 共享 | 类元信息、运行时常量池 | OutOfMemoryError |
| 直接内存 | --- | NIO DirectByteBuffer 引用的堆外内存 | OutOfMemoryError |
4.2 Java 8 关键变化:永久代 → 元空间
| 维度 | 永久代(≤ Java 7) | 元空间(Java 8+) |
|---|---|---|
| 位置 | 堆内 | 本地内存(堆外) |
| 容量 | 固定,-XX:MaxPermSize | 默认仅受物理内存限制,-XX:MaxMetaspaceSize |
| 优点 | --- | 不易 OOM、字符串常量池迁至堆便于回收 |
4.3 可运行示例:栈溢出与堆溢出
java
// StackOverflowError 复现:无线程出口的递归
public class StackOverflowDemo {
static int depth = 0;
public static void main(String[] args) {
try {
recurse();
} catch (StackOverflowError e) {
System.out.println("栈深度: " + depth); // 默认 -Xss 下约 1w+
}
}
static void recurse() { depth++; recurse(); }
}
java
// OutOfMemoryError: Java heap space 复现
import java.util.ArrayList;
import java.util.List;
public class HeapOomDemo {
public static void main(String[] args) {
List<byte[]> list = new ArrayList<>();
while (true) list.add(new byte[1024 * 1024]); // 每次 1MB,撑爆堆
}
}
bash
# 堆溢出:-Xmx 调小便于复现
javac HeapOomDemo.java && java -Xmx10m HeapOomDemo
# 栈溢出:调小线程栈
javac StackOverflowDemo.java && java -Xss256k StackOverflowDemo
4.4 JMM:主内存 / 工作内存与 happens-before
- 所有变量存于主内存 ;线程操作变量时必须拷贝到工作内存再写回。
volatile两条语义:可见性(写立即刷回主内存)+ 禁止指令重排(内存屏障)。- happens-before 常用规则速查表:
| 规则 | 说明 |
|---|---|
| 程序次序 | 单线程内书写在前先发生 |
| 监视器锁 | unlock 先于后续 lock |
| volatile | 写先于后续读 |
| 传递性 | A→B、B→C 则 A→C |
相关深度笔记:\[JVM-内存结构-知识点]
5. 功能域二:类加载机制 ★★★
5.1 类生命周期(7 阶段)
加载 → 验证 → 准备 → 解析 → 初始化 → 使用 → 卸载
- 加载:通过类全限定名找到字节码,生成 java.lang.Class 对象;
- 准备:为 static 变量分配内存并赋零值;
- 初始化:真正执行 static 赋值与 static 块(触发时机:new、反射、初始化子类、执行 main 类等)。
5.2 双亲委派模型
#mermaid-svg-3unK0L5K9FQ8B7S5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-3unK0L5K9FQ8B7S5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-3unK0L5K9FQ8B7S5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-3unK0L5K9FQ8B7S5 .error-icon{fill:#552222;}#mermaid-svg-3unK0L5K9FQ8B7S5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-3unK0L5K9FQ8B7S5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-3unK0L5K9FQ8B7S5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-3unK0L5K9FQ8B7S5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-3unK0L5K9FQ8B7S5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-3unK0L5K9FQ8B7S5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-3unK0L5K9FQ8B7S5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-3unK0L5K9FQ8B7S5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-3unK0L5K9FQ8B7S5 .marker.cross{stroke:#333333;}#mermaid-svg-3unK0L5K9FQ8B7S5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-3unK0L5K9FQ8B7S5 p{margin:0;}#mermaid-svg-3unK0L5K9FQ8B7S5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-3unK0L5K9FQ8B7S5 .cluster-label text{fill:#333;}#mermaid-svg-3unK0L5K9FQ8B7S5 .cluster-label span{color:#333;}#mermaid-svg-3unK0L5K9FQ8B7S5 .cluster-label span p{background-color:transparent;}#mermaid-svg-3unK0L5K9FQ8B7S5 .label text,#mermaid-svg-3unK0L5K9FQ8B7S5 span{fill:#333;color:#333;}#mermaid-svg-3unK0L5K9FQ8B7S5 .node rect,#mermaid-svg-3unK0L5K9FQ8B7S5 .node circle,#mermaid-svg-3unK0L5K9FQ8B7S5 .node ellipse,#mermaid-svg-3unK0L5K9FQ8B7S5 .node polygon,#mermaid-svg-3unK0L5K9FQ8B7S5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-3unK0L5K9FQ8B7S5 .rough-node .label text,#mermaid-svg-3unK0L5K9FQ8B7S5 .node .label text,#mermaid-svg-3unK0L5K9FQ8B7S5 .image-shape .label,#mermaid-svg-3unK0L5K9FQ8B7S5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-3unK0L5K9FQ8B7S5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-3unK0L5K9FQ8B7S5 .rough-node .label,#mermaid-svg-3unK0L5K9FQ8B7S5 .node .label,#mermaid-svg-3unK0L5K9FQ8B7S5 .image-shape .label,#mermaid-svg-3unK0L5K9FQ8B7S5 .icon-shape .label{text-align:center;}#mermaid-svg-3unK0L5K9FQ8B7S5 .node.clickable{cursor:pointer;}#mermaid-svg-3unK0L5K9FQ8B7S5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-3unK0L5K9FQ8B7S5 .arrowheadPath{fill:#333333;}#mermaid-svg-3unK0L5K9FQ8B7S5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-3unK0L5K9FQ8B7S5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-3unK0L5K9FQ8B7S5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3unK0L5K9FQ8B7S5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-3unK0L5K9FQ8B7S5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3unK0L5K9FQ8B7S5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-3unK0L5K9FQ8B7S5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-3unK0L5K9FQ8B7S5 .cluster text{fill:#333;}#mermaid-svg-3unK0L5K9FQ8B7S5 .cluster span{color:#333;}#mermaid-svg-3unK0L5K9FQ8B7S5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-3unK0L5K9FQ8B7S5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-3unK0L5K9FQ8B7S5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-3unK0L5K9FQ8B7S5 .icon-shape,#mermaid-svg-3unK0L5K9FQ8B7S5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-3unK0L5K9FQ8B7S5 .icon-shape p,#mermaid-svg-3unK0L5K9FQ8B7S5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-3unK0L5K9FQ8B7S5 .icon-shape .label rect,#mermaid-svg-3unK0L5K9FQ8B7S5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-3unK0L5K9FQ8B7S5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-3unK0L5K9FQ8B7S5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-3unK0L5K9FQ8B7S5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 加载请求
应用类加载器
classpath
扩展类加载器
jre/lib/ext
启动类加载器
rt.jar
- 收到加载请求先委派父加载器,父加载不了才自己加载------保证核心类库(如 java.lang.String)不被篡改。
java
// 查看一个类的加载器层级(可运行)
public class LoaderDemo {
public static void main(String[] args) {
ClassLoader cl = String.class.getClassLoader();
System.out.println("String 的加载器: " + cl); // null = 启动类加载器(C++ 实现)
System.out.println("自身类的加载器: " + LoaderDemo.class.getClassLoader());
// 输出: sun.misc.Launcher$AppClassLoader
}
}
5.3 打破双亲委派
- 线程上下文类加载器(Thread Context ClassLoader) :JDBC 等 SPI 场景,核心库反向加载应用类------
DriverManager.getConnection()内部即通过它加载厂商驱动,是学习"打破双亲委派"最经典的案例。
6. 功能域三:字节码与执行引擎
6.1 字节码文件结构与反编译
bash
javap -c -v Demo.class # 查看常量池、方法字节码指令
| 结构块 | 说明 |
|---|---|
| 魔数 CAFEBABE | 文件头标识 |
| 版本号 | 主版本 52 = Java 8 |
| 常量池 | 字面量与符号引用,字节码文件最大结构 |
| 访问标志 | public/final 等 |
| 方法表 | 含 Code 属性(实际字节码指令) |
6.2 执行方式:解释执行 + 即时编译(JIT)
| 方式 | 原理 | 特点 |
|---|---|---|
| 解释执行 | 逐条翻译字节码执行 | 启动快、运行慢 |
| JIT(C1/C2) | 热点代码编译成本地机器码 | 启动慢、运行快 |
- Java 8 默认开启分层编译(-XX:+TieredCompilation):C1 快速编译保启动,C2 深度优化保峰值;
- Lambda 依赖
invokedynamic指令,是 Java 8 字节码层面的重要变化。
6.3 栈帧结构
局部变量表 + 操作数栈 + 动态链接 + 方法返回地址------方法调用本质是栈帧的入栈/出栈,理解栈帧是理解虚拟机栈的关键。
7. 功能域四:垃圾回收 GC ★★★
7.1 判定垃圾:可达性分析
- GC Roots 包括:虚拟机栈引用、静态变量、常量、JNI 引用等;从根出发不可达的对象即垃圾。
7.2 分代理论与堆结构
| 区域 | 默认占比 | 回收动作 |
|---|---|---|
| 新生代 Eden : S0 : S1 | 8 : 1 : 1 | Minor GC(复制算法) |
| 老年代 | 新生代 : 老年代 = 1 : 2 | Major/Full GC |
| 算法 | 思路 | 缺点 |
|---|---|---|
| 标记-清除 | 标记垃圾后直接清除 | 内存碎片 |
| 复制 | 存活对象搬到另一半 | 空间利用率 50% |
| 标记-整理 | 存活对象向一端移动 | 移动对象成本高 |
7.3 Java 8 垃圾收集器速查
| 收集器 | 线程 | 关注点 | 启用参数 |
|---|---|---|---|
| Serial / Serial Old | 单 | 内存占用小(客户端默认) | -XX:+UseSerialGC |
| ParNew | 多 | 配合 CMS 的新生代收集器 | -XX:+UseParNewGC |
| Parallel Scavenge / Parallel Old | 多 | 吞吐量优先(Java 8 服务端默认) | -XX:+UseParallelGC |
| CMS | 多 | 响应时间优先,低停顿 | -XX:+UseConcMarkSweepGC |
| G1 | 多 | 大堆、可预测停顿(Java 8 可用,9 起默认) | -XX:+UseG1GC |
关键认知 :Java 8 服务端机器默认 Parallel Scavenge + Parallel Old;CMS 是并发收集器(初始标记/并发标记/重新标记/并发清除四阶段,并发标记使用三色标记法);G1 在 Java 8 已基本成熟但非默认。
7.4 GC 日志(Java 8 风格)
bash
# 输出 GC 日志(Java 8 参数风格,9+ 改用 -Xlog:gc)
java -Xms512m -Xmx512m \
-XX:+PrintGCDetails -XX:+PrintGCDateStamps \
-Xloggc:gc.log App
# 实时查看 GC 统计(每 1000ms 一次)
jstat -gcutil <pid> 1000
8. 功能域五:JVM 参数、监控与排查工具
8.1 常用参数分类速查
| 分类 | 参数 | 说明 |
|---|---|---|
| 堆 | -Xms / -Xmx | 初始/最大堆(生产建议相等,避免扩容抖动) |
| 新生代 | -Xmn / -XX:NewRatio | 新生代大小 / 新生老年代比例 |
| 栈 | -Xss | 线程栈大小 |
| 元空间 | -XX:MetaspaceSize / -XX:MaxMetaspaceSize | 触发 GC 阈值 / 上限 |
| 直接内存 | -XX:MaxDirectMemorySize | NIO 堆外内存上限 |
8.2 工具速查
| 工具 | 用途 | 典型命令 |
|---|---|---|
| jps | 列出 Java 进程 | jps -l |
| jstat | GC/类加载统计 | jstat -gcutil 1000 |
| jinfo | 查看运行中参数 | jinfo -flags |
| jmap | 堆快照 | jmap -dump:format=b,file=heap.hprof |
| jstack | 线程栈(死锁排查) | jstack | grep -A10 deadlock |
| jcmd | 综合命令 | jcmd GC.heap_dump |
| jvisualvm / MAT | 可视化 / 堆分析 | 分析 heap.hprof 找大对象与泄漏 |
8.3 OOM 排查对照表
| 报错信息 | 原因方向 | 排查动作 |
|---|---|---|
| Java heap space | 堆不够/泄漏 | jmap dump + MAT 分析大对象 |
| Metaspace | 类元信息过多(动态代理/热部署) | 检查 ClassLoader 泄漏 |
| unable to create new native thread | 线程数超限 | ulimit -u、线程池大小 |
| Direct buffer memory | 堆外内存不足 | 检查 NIO 使用与 -XX:MaxDirectMemorySize |
9. 版本演进:JVM 简史与 Java 8 的关键变化
| 版本 | 关键变化 |
|---|---|
| JDK 6 | CMS、jmap/jstack 等工具成熟 |
| JDK 7 | G1 试验性引入、NIO.2、字符串常量池移入堆 |
| JDK 8(2014-03,LTS) | 永久代→元空间、Lambda/invokedynamic、Nashorn JS 引擎、分层编译默认开启、默认 Parallel GC、u20 起字符串去重(-XX:+UseStringDeduplication) |
| JDK 9+ | 模块化、G1 成为默认收集器;11 为下一个 LTS;14 移除 CMS、引入 ZGC/Shenandoah |
关键认知:Java 8 是"老参数体系"(PrintGCDetails/Xloggc)与"老收集器组合"(CMS 可用、Parallel 默认)的完整收官版本,新版本的知识(G1 默认、ZGC、-Xlog 日志)都从它演化而来。
10. 学习路线图
#mermaid-svg-FJi91Qv7zmEVrzP4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FJi91Qv7zmEVrzP4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FJi91Qv7zmEVrzP4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FJi91Qv7zmEVrzP4 .error-icon{fill:#552222;}#mermaid-svg-FJi91Qv7zmEVrzP4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FJi91Qv7zmEVrzP4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FJi91Qv7zmEVrzP4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FJi91Qv7zmEVrzP4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FJi91Qv7zmEVrzP4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FJi91Qv7zmEVrzP4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FJi91Qv7zmEVrzP4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FJi91Qv7zmEVrzP4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FJi91Qv7zmEVrzP4 .marker.cross{stroke:#333333;}#mermaid-svg-FJi91Qv7zmEVrzP4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FJi91Qv7zmEVrzP4 p{margin:0;}#mermaid-svg-FJi91Qv7zmEVrzP4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FJi91Qv7zmEVrzP4 .cluster-label text{fill:#333;}#mermaid-svg-FJi91Qv7zmEVrzP4 .cluster-label span{color:#333;}#mermaid-svg-FJi91Qv7zmEVrzP4 .cluster-label span p{background-color:transparent;}#mermaid-svg-FJi91Qv7zmEVrzP4 .label text,#mermaid-svg-FJi91Qv7zmEVrzP4 span{fill:#333;color:#333;}#mermaid-svg-FJi91Qv7zmEVrzP4 .node rect,#mermaid-svg-FJi91Qv7zmEVrzP4 .node circle,#mermaid-svg-FJi91Qv7zmEVrzP4 .node ellipse,#mermaid-svg-FJi91Qv7zmEVrzP4 .node polygon,#mermaid-svg-FJi91Qv7zmEVrzP4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FJi91Qv7zmEVrzP4 .rough-node .label text,#mermaid-svg-FJi91Qv7zmEVrzP4 .node .label text,#mermaid-svg-FJi91Qv7zmEVrzP4 .image-shape .label,#mermaid-svg-FJi91Qv7zmEVrzP4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-FJi91Qv7zmEVrzP4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FJi91Qv7zmEVrzP4 .rough-node .label,#mermaid-svg-FJi91Qv7zmEVrzP4 .node .label,#mermaid-svg-FJi91Qv7zmEVrzP4 .image-shape .label,#mermaid-svg-FJi91Qv7zmEVrzP4 .icon-shape .label{text-align:center;}#mermaid-svg-FJi91Qv7zmEVrzP4 .node.clickable{cursor:pointer;}#mermaid-svg-FJi91Qv7zmEVrzP4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FJi91Qv7zmEVrzP4 .arrowheadPath{fill:#333333;}#mermaid-svg-FJi91Qv7zmEVrzP4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FJi91Qv7zmEVrzP4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FJi91Qv7zmEVrzP4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FJi91Qv7zmEVrzP4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FJi91Qv7zmEVrzP4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FJi91Qv7zmEVrzP4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FJi91Qv7zmEVrzP4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FJi91Qv7zmEVrzP4 .cluster text{fill:#333;}#mermaid-svg-FJi91Qv7zmEVrzP4 .cluster span{color:#333;}#mermaid-svg-FJi91Qv7zmEVrzP4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FJi91Qv7zmEVrzP4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FJi91Qv7zmEVrzP4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-FJi91Qv7zmEVrzP4 .icon-shape,#mermaid-svg-FJi91Qv7zmEVrzP4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FJi91Qv7zmEVrzP4 .icon-shape p,#mermaid-svg-FJi91Qv7zmEVrzP4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FJi91Qv7zmEVrzP4 .icon-shape .label rect,#mermaid-svg-FJi91Qv7zmEVrzP4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FJi91Qv7zmEVrzP4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FJi91Qv7zmEVrzP4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FJi91Qv7zmEVrzP4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 阶段一:内存结构
区域职责 + OOM 复现
阶段二:类加载
双亲委派 + SPI
阶段三:GC
算法 + 收集器 + 日志解读
阶段四:执行引擎
JIT + 字节码
阶段五:实战
调优 + MAT 排查
| 阶段 | 内容 | 产出 |
|---|---|---|
| ① 入门(1 周) | 运行时数据区、类加载生命周期、双亲委派 | 能画内存分区图、手写 OOM/栈溢出 demo |
| ② 进阶(1 周) | GC 算法、Java 8 各收集器、JMM/happens-before | 能读懂 GC 日志并判断收集器 |
| ③ 实战(持续) | jstat/jmap/jstack/MAT 排查线上问题 | 完成一次真实 OOM 或内存泄漏定位 |
11. 总结
一句话概括:学 Java 8 JVM 就是啃五块骨头------内存结构打底、类加载管入口、执行引擎管运行、GC 管回收、参数工具管观测;五者以"字节码 → 运行时数据区"为主轴串成一张网。
上手路径:
- 先记住运行时数据区 6 大区域分工(表格即可,不必深究);
- 亲手复现 StackOverflowError 与 Java heap space OOM,建立直观体感;
- 通读双亲委派源码(ClassLoader#loadClass)------这是最好入门的 JVM 源码;
- 跑一个应用,用 jstat + GC 日志观察 Parallel GC 的 Minor GC / Full GC 节奏;
- 进阶时转向 CMS/G1 停顿模型、JIT 逃逸分析、JMM 重排序实验。
关注我精彩还在后面......