Java学习第六十部分——JVM

发布于:2025-07-23 ⋅ 阅读:(13) ⋅ 点赞:(0)

目录

一. 关键概述

二. 核心功能

三. 组成架构

1. 类加载子系统 (ClassLoader)

2. 运行时数据区 (Runtime Data Areas)

3. 执行引擎 (Execution Engine)

四. 类加载机制

五. 垃圾回收 (GC)

六. JIT 编译器 (Just-In-Time)

七. 调优参数示例

八. 常见问题与工具

九. 与 JDK/JRE 的关系

十. 调优与监控

十一. 常见实现

十二. 简单示例

十三. 总结归纳


一. 关键概述

       Java 虚拟机(JVM,Java Virtual Machine)是 Java 平台的核心组成部分,负责将编译后的字节码(`.class` 文件)解释或编译为机器码,并在不同操作系统上实现“一次编写,到处运行”(Write Once, Run Anywhere)的跨平台特性。

二. 核心功能

  • 跨平台执行:将字节码翻译成不同操作系统的本地机器指令。

  • 内存管理:自动分配/回收内存(堆、栈等),避免手动管理错误。

  • 垃圾回收 (GC):自动回收无用的对象内存。

  • 字节码执行:通过解释器或 JIT 编译器执行字节码。

三. 组成架构

1. 类加载子系统 (ClassLoader)
组件 功能描述 关键特性
Bootstrap ClassLoader 加载 JAVA_HOME/lib 的核心类库(如 rt.jar 由 C++ 实现,JVM 自身的一部分
Extension ClassLoader 加载 JAVA_HOME/lib/ext 目录的扩展类库 继承自 URLClassLoader,父加载器为 Bootstrap
Application ClassLoader 加载用户类路径(classpath)的类 默认线程上下文类加载器,父加载器为 Extension
双亲委派模型 加载类时优先委派父类加载器处理 避免核心类被篡改(如自定义 java.lang.String),确保安全性和类唯一性

2. 运行时数据区 (Runtime Data Areas)
内存区域 存储内容 特性
方法区 (Method Area) 类元数据(类名、字段、方法)、常量池、静态变量 JDK 8+ 由元空间 (Metaspace) 实现,使用本地内存,替代永久代(PermGen)
堆 (Heap) 对象实例和数组 垃圾回收主区域,分为:
- 新生代(Eden + Survivor From/To)
- 老年代
虚拟机栈 (JVM Stack) 每个线程私有,存储栈帧(局部变量表、操作数栈、动态链接、方法出口) 方法调用压栈,返回弹栈;可能抛出 StackOverflowError
本地方法栈 服务于 Native 方法(如 JNI 调用的 C/C++ 代码) 与虚拟机栈类似,但针对本地方法
程序计数器 (PC Register) 记录当前线程执行的字节码指令地址 唯一不会发生 OOM 的区域,线程私有

3. 执行引擎 (Execution Engine)
组件 功能描述 关键实现
解释器 (Interpreter) 逐行解释字节码为机器码执行 启动速度快,但运行时效率低
JIT 编译器 将热点代码(高频方法/循环)编译为本地机器码 HotSpot 使用分层编译:
- C1 编译器(客户端,快速优化)
- C2 编译器(服务端,深度优化)
垃圾回收器 (GC) 自动回收无引用对象的内存 主流算法与收集器
- 新生代:复制算法(Parallel Scavenge)
- 老年代:标记-清除/整理(CMS)
G1 GC(JDK9+ 默认):区域化分代 + 可预测停顿
ZGC(JDK11+):低延迟(<10ms)、TB 级

核心关系总结

  • 类加载 → 运行时数据区:

ClassLoader 加载的类元数据存储于方法区,对象实例分配在堆中。

  • 执行引擎 → 运行时数据区:

解释器/JIT 执行栈中方法的字节码;GC 管理堆内存的回收。

  • 线程私有区域:

每个线程独立拥有:虚拟机栈、本地方法栈、程序计数器。

四. 类加载机制

类加载分三个阶段:
1. **加载 (Loading)**  
   - 通过类加载器(`ClassLoader`)加载 `.class` 文件到内存。
   - 类加载器层级:
     - **Bootstrap ClassLoader**(加载核心库如 `rt.jar`)
     - **Extension ClassLoader**(加载扩展库)
     - **Application ClassLoader**(加载用户类路径)
     - **自定义 ClassLoader**(用户扩展)。
2. **链接 (Linking)**  
   - 验证字节码合法性 → 准备(为静态变量分配内存)→ 解析(符号引用转直接引用)。
3. **初始化 (Initialization)**  
   - 执行静态代码块和静态变量赋值(如 `static int x = 10;`)。

五. 垃圾回收 (GC)

- **回收对象**:无引用指向的对象(如超出作用域的局部变量)。
- **GC 算法**:
  - **分代收集**:堆分为 **新生代 (Young)** 和 **老年代 (Old)**。
    - 新生代:使用 **复制算法**(Eden + Survivor 区)。
    - 老年代:使用 **标记-清除** 或 **标记-整理** 算法。
  - **垃圾收集器**:
    - **Serial GC**:单线程,适合小应用。
    - **Parallel GC**(默认):多线程,吞吐量优先。
    - **CMS** / **G1 GC**:低延迟,减少 STW(Stop-The-World)时间。
    - **ZGC** / **Shenandoah**(JDK 15+):超低延迟(<10ms)。

六. JIT 编译器 (Just-In-Time)

- **热点代码优化**:频繁执行的字节码会被编译成本地机器码(如循环、高频方法)。
- **解释器 vs JIT**:解释器逐行执行字节码(启动快);JIT 编译后执行(运行快)。

七. 调优参数示例

# 堆内存设置
-Xms512m    # 初始堆大小(默认物理内存 1/64)
-Xmx1024m   # 最大堆大小(默认物理内存 1/4)
-XX:NewRatio=2  # 老年代:新生代 = 2:1
-XX:SurvivorRatio=8  # Eden:Survivor = 8:1

# 垃圾回收器选择
-XX:+UseG1GC        # 启用 G1 收集器
-XX:+UseConcMarkSweepGC  # 启用 CMS 收集器

# 元空间设置(JDK 8+)
-XX:MetaspaceSize=128m  
-XX:MaxMetaspaceSize=256m

八. 常见问题与工具

- **内存泄漏**:对象被意外保留引用(如静态集合类持续增长)。
- **OOM (OutOfMemoryError)**:堆/元空间不足。
- **诊断工具**:
  - **jconsole** / **VisualVM**:图形化监控堆、线程、类加载。
  - **jstack**:分析线程堆栈(死锁检测)。
  - **jmap**:导出堆内存快照(配合 **MAT** 工具分析内存泄漏)。
  - **jstat**:监控 GC 状态(`jstat -gcutil <pid> 1000`)。

九. 与 JDK/JRE 的关系

- **JDK (Java Development Kit)**:开发工具包(含 JRE + 编译器 `javac`)。
- **JRE (Java Runtime Environment)**:运行环境(含 JVM + 基础库)。
- **JVM**:执行引擎,是 JRE 的子集。

十. 调优与监控

- **常用参数**:
  - 堆大小:`-Xms`(初始堆)、`-Xmx`(最大堆)。
  - 新生代比例:`-XX:NewRatio`。
  - GC 日志:`-Xlog:gc*`(JDK 9+)。
  - 元空间:`-XX:MaxMetaspaceSize`。
- **监控工具**:
  - **JVisualVM**:可视化监控线程、堆、GC。
  - **JConsole**:实时查看内存、线程、类加载。
  - **jstack**:查看线程堆栈(定位死锁)。
  - **jmap**:生成堆转储(`jmap -dump` 分析内存泄漏)。

十一. 常见实现

- **HotSpot**(Oracle/OpenJDK 默认):支持 JIT 和多种 GC。
- **OpenJ9**(IBM):低内存占用,适合云原生。
- **GraalVM**:多语言支持(Java/Python/JS),原生镜像(AOT 编译)。

十二. 简单示例

// 内存泄漏示例:静态集合持有对象引用
public class MemoryLeak {
    private static final List<Object> list = new ArrayList<>();
    public void addData() {
        while (true) {
            list.add(new byte[1024 * 1024]); // 持续占用内存
        }
    }
}

排查步骤:
1. 使用 `jmap -dump:format=b,file=heap.hprof <pid>` 生成堆转储。
2. 通过 MAT 或 VisualVM 分析泄漏路径(如 `list` 持续增长)。

十三. 总结归纳

JVM 是 Java 生态的基石,理解其内存模型、类加载、GC 机制是优化性能的关键。掌握 JVM 调优和诊断工具,能有效解决内存溢出、高延迟等问题。JVM 通过抽象操作系统差异、自动化内存管理和高效的执行引擎,成为 Java 高性能和跨平台能力的基石。理解其原理和调优技巧,是 Java 开发者进阶的必经之路。


网站公告

今日签到

点亮在社区的每一天
去签到