讲透 JVM(Java Virtual Machine)_讲透中药·张景明
今天,我们讲透 JVM(Java Virtual Machine),从 体系结构、核心组件、内存模型、类加载机制、执行引擎、垃圾回收、调优和常见问题 这些方面系统展开。内容会比较全,你可以当作一个 JVM 体系速成+深度指南。
一、JVM 的本质
- 虚拟机:一种抽象的计算机,屏蔽硬件和操作系统差异,让 Java 程序“一次编译,到处运行”。
- 核心目标:
- 跨平台
- 内存管理(自动 GC)
- 安全沙箱(类加载隔离、字节码校验)
- 高性能(JIT、逃逸分析、分层编译)
二、JVM 架构
JVM 可以分为四大模块:
- 类加载子系统(Class Loader Subsystem)
- 负责加载 .class 字节码文件到内存
- 双亲委派模型:
- Bootstrap ClassLoader(加载 rt.jar 等核心类)
- Extension ClassLoader(加载扩展库 jre/lib/ext)
- Application ClassLoader(加载应用类路径下的类)
- 自定义 ClassLoader
- 特点:避免核心类被篡改(比如你写个假的 java.lang.String 也不会生效)。
- 运行时数据区(Runtime Data Area)
JVM 的内存模型,核心: - 线程私有
- 程序计数器(Program Counter)
- Java 虚拟机栈(栈帧:局部变量表、操作数栈、动态链接、方法出口)
- 本地方法栈(执行 native 方法用)
- 线程共享
- 堆(Heap):存放对象实例,GC 管辖重点
- 方法区(Method Area / 元空间 Metaspace):类元信息(类加载后的结构)、运行时常量池、静态变量
- 运行时常量池:字符串常量池、符号引用
- 执行引擎(Execution Engine)
- 解释器(Interpreter):逐条解释执行字节码,启动快但慢
- JIT(Just-In-Time 编译器):热点代码编译成本地机器码,执行快
- 分层编译(Tiered Compilation):解释 + C1(客户端编译)+ C2(服务端编译)协作
- 本地接口(Native Interface)
- 与操作系统交互,如文件 I/O、网络、JNI。
三、JVM 内存模型(JMM)
JMM 是 线程间通信的抽象模型,规定了 主内存(堆内存) 与 工作内存(线程栈内存) 的交互规则。
关键点:
- 线程读写变量 → 必须通过主内存交互
- 指令重排、内存可见性 → 需要 volatile、synchronized、final、原子类 来保证
- happens-before 原则:
- 程序顺序规则
- 锁规则
- volatile 规则
- 线程启动/终止规则
四、垃圾回收(GC)
1. 对象生命周期
- 存活判定:
- 引用计数法(简单但不能解决循环引用)
- 可达性分析(主流方法,从 GC Roots 出发追踪可达对象)
2. 分代收集理论
- 新生代(Young Gen):Eden + Survivor
- Minor GC:频繁、快
- 老年代(Old Gen):存放长期存活对象
- Major GC / Full GC:慢、STW(Stop the World)
- 元空间(Metaspace):存放类元信息
3. 常见 GC 算法
- 复制算法(Copying) → 新生代
- 标记-清除(Mark-Sweep) → 老年代
- 标记-整理(Mark-Compact) → 老年代
4. 常见 GC 垃圾收集器
- Serial / Serial Old:单线程,简单,适合小内存
- Parallel / Parallel Old:多线程,吞吐量优先
- CMS(Concurrent Mark-Sweep):并发,低延迟,但有碎片化
- G1(Garbage First):分区化,预测停顿时间,主流
- ZGC、Shenandoah:超低延迟 GC(亚毫秒级停顿),大内存场景
五、类加载机制
- 生命周期:加载 → 验证 → 准备 → 解析 → 初始化 → 使用 → 卸载
- 懒加载:只有在首次使用类时才会触发加载
- 反射/动态代理:依赖运行时类加载
六、调优与监控
常见 JVM 参数
- 堆大小:-Xms -Xmx
- 新生代/老年代比例:-XX:NewRatio
- Survivor 比例:-XX:SurvivorRatio
- GC 类型:-XX:+UseG1GC 等
- 元空间:-XX:MetaspaceSize
常用工具
- jps / jstat / jmap / jstack
- VisualVM
- Arthas
- GC 日志:-XX:+PrintGCDetails -Xlog:gc*
七、常见问题
- OOM(OutOfMemoryError)分类
- Java heap space
- Metaspace
- GC overhead limit exceeded
- Direct buffer memory
- Unable to create new native thread
- 频繁 Full GC
- 内存泄漏
- 元空间过小
- 大量对象进入老年代
- 性能瓶颈
- GC 停顿长
- 锁竞争
- 内存抖动(频繁对象创建销毁)
八、总结
JVM 就是一个 运行时环境 + 内存管理 + 执行优化引擎,关键要点:
- 内存结构(堆/栈/方法区/PC)
- 执行模型(解释 + JIT + 分层编译)
- 类加载机制(双亲委派)
- 垃圾回收(分代、收集器选择)
- 调优方法(参数、监控工具)
建议你:
- 先用 jvisualvm / arthas 观察项目运行时的堆、线程、GC 行为
- 再通过调参数,比如换不同的 GC 收集器,看性能差异
- 最后结合 JMM 和并发包源码,理解线程安全和内存语义