Java虚拟机(JVM)

JVM简介

Java虚拟机(JVM)是Java平台的核心组件,它负责执行Java字节码,提供内存管理、垃圾回收等功能。JVM使得Java程序具有"一次编写,到处运行"的特性。

JVM架构

// JVM主要组件 1. 类加载器(Class Loader) 2. 运行时数据区(Runtime Data Areas) 3. 执行引擎(Execution Engine) 4. 本地方法接口(Native Method Interface)

类加载器

类加载器负责将.class文件加载到JVM中,并生成对应的Class对象。

// 类加载过程 1. 加载(Loading) 2. 验证(Verification) 3. 准备(Preparation) 4. 解析(Resolution) 5. 初始化(Initialization) 6. 使用(Using) 7. 卸载(Unloading) // 类加载器层次结构 - 启动类加载器(Bootstrap ClassLoader) - 扩展类加载器(Extension ClassLoader) - 应用类加载器(Application ClassLoader) - 自定义类加载器(User-defined ClassLoader)

运行时数据区

JVM运行时数据区包括方法区、堆、虚拟机栈、本地方法栈和程序计数器。

// 运行时数据区结构 public class RuntimeDataAreas { // 方法区(Method Area) // 存储类信息、常量、静态变量等 // 堆(Heap) // 存储对象实例和数组 // 虚拟机栈(VM Stack) // 存储局部变量表、操作数栈等 // 本地方法栈(Native Method Stack) // 为本地方法服务 // 程序计数器(Program Counter Register) // 当前线程执行的字节码行号指示器 }

垃圾回收

JVM的垃圾回收机制自动管理内存,回收不再使用的对象。

// 垃圾回收算法 1. 标记-清除(Mark-Sweep) 2. 复制(Copying) 3. 标记-整理(Mark-Compact) 4. 分代收集(Generational Collection) // 垃圾收集器 - Serial收集器 - ParNew收集器 - Parallel Scavenge收集器 - CMS收集器 - G1收集器 - ZGC收集器

JVM调优

通过调整JVM参数可以优化程序性能。

// 常用JVM参数 -Xms2048m // 初始堆大小 -Xmx2048m // 最大堆大小 -XX:NewRatio=2 // 新生代与老年代的比例 -XX:SurvivorRatio=8 // Eden区与Survivor区的比例 // 垃圾收集器选择 -XX:+UseG1GC // 使用G1收集器 -XX:+UseConcMarkSweepGC // 使用CMS收集器 // GC日志 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log

Java内存模型

Java内存模型(JMM)定义了线程与主内存之间的交互规则。

// 内存模型的关键概念 public class MemoryModel { // 主内存(Main Memory) // 所有线程共享的内存区域 // 工作内存(Working Memory) // 每个线程私有的内存区域 // 内存间交互操作 // lock(锁定) // unlock(解锁) // read(读取) // load(载入) // use(使用) // assign(赋值) // store(存储) // write(写入) }

JVM工具

JDK提供了多种工具用于监控和调优JVM。

// 常用JVM工具 1. jps:显示Java进程 2. jstat:显示JVM统计信息 3. jinfo:显示JVM配置信息 4. jmap:生成堆转储快照 5. jhat:分析堆转储文件 6. jstack:显示线程快照 7. jconsole:图形化监控工具 8. VisualVM:多合一故障处理工具

实践练习

练习1:JVM参数调优

public class JVMTuningDemo {
    public static void main(String[] args) {
        // 创建一个内存泄漏的示例
        List list = new ArrayList<>();
        while (true) {
            list.add(new byte[1024 * 1024]); // 每次分配1MB
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}