讲透 JVM(Java Virtual Machine)_讲透中药·张景明

deer332025-10-13技术文章36

今天,我们讲透 JVM(Java Virtual Machine),从 体系结构、核心组件、内存模型、类加载机制、执行引擎、垃圾回收、调优和常见问题 这些方面系统展开。内容会比较全,你可以当作一个 JVM 体系速成+深度指南


一、JVM 的本质

  • 虚拟机:一种抽象的计算机,屏蔽硬件和操作系统差异,让 Java 程序“一次编译,到处运行”。
  • 核心目标
  • 跨平台
  • 内存管理(自动 GC)
  • 安全沙箱(类加载隔离、字节码校验)
  • 高性能(JIT、逃逸分析、分层编译)

二、JVM 架构

JVM 可以分为四大模块:

  1. 类加载子系统(Class Loader Subsystem)
  2. 负责加载 .class 字节码文件到内存
  3. 双亲委派模型
  4. Bootstrap ClassLoader(加载 rt.jar 等核心类)
  5. Extension ClassLoader(加载扩展库 jre/lib/ext)
  6. Application ClassLoader(加载应用类路径下的类)
  7. 自定义 ClassLoader
  8. 特点:避免核心类被篡改(比如你写个假的 java.lang.String 也不会生效)。
  9. 运行时数据区(Runtime Data Area)
    JVM 的内存模型,核心:
  10. 线程私有
  11. 程序计数器(Program Counter)
  12. Java 虚拟机栈(栈帧:局部变量表、操作数栈、动态链接、方法出口)
  13. 本地方法栈(执行 native 方法用)
  14. 线程共享
  15. 堆(Heap):存放对象实例,GC 管辖重点
  16. 方法区(Method Area / 元空间 Metaspace):类元信息(类加载后的结构)、运行时常量池、静态变量
  17. 运行时常量池:字符串常量池、符号引用
  18. 执行引擎(Execution Engine)
  19. 解释器(Interpreter):逐条解释执行字节码,启动快但慢
  20. JIT(Just-In-Time 编译器):热点代码编译成本地机器码,执行快
  21. 分层编译(Tiered Compilation):解释 + C1(客户端编译)+ C2(服务端编译)协作
  22. 本地接口(Native Interface)
  23. 与操作系统交互,如文件 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*

七、常见问题

  1. OOM(OutOfMemoryError)分类
  2. Java heap space
  3. Metaspace
  4. GC overhead limit exceeded
  5. Direct buffer memory
  6. Unable to create new native thread
  7. 频繁 Full GC
  8. 内存泄漏
  9. 元空间过小
  10. 大量对象进入老年代
  11. 性能瓶颈
  12. GC 停顿长
  13. 锁竞争
  14. 内存抖动(频繁对象创建销毁)

八、总结

JVM 就是一个 运行时环境 + 内存管理 + 执行优化引擎,关键要点:

  1. 内存结构(堆/栈/方法区/PC)
  2. 执行模型(解释 + JIT + 分层编译)
  3. 类加载机制(双亲委派)
  4. 垃圾回收(分代、收集器选择)
  5. 调优方法(参数、监控工具)

建议你:

  • 先用 jvisualvm / arthas 观察项目运行时的堆、线程、GC 行为
  • 再通过调参数,比如换不同的 GC 收集器,看性能差异
  • 最后结合 JMM 和并发包源码,理解线程安全和内存语义