【JVM 深入了解】JVM 到底包含什么?

👉博主介绍: 博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家,WEB架构师,阿里云专家博主,华为云云享专家,51CTO 专家博主

⛪️ 个人社区:个人社区

💞 个人主页:个人主页

🙉 专栏地址: ✅ Java 中级

🙉八股文专题:剑指大厂,手撕 Java 八股文

文章目录

      • [1. JVM 架构](#1. JVM 架构)
      • [2. 垃圾收集机制](#2. 垃圾收集机制)
      • [3. 性能优化](#3. 性能优化)
      • [4. 内存模型](#4. 内存模型)
      • [5. 类加载过程](#5. 类加载过程)
      • [6. 字节码执行](#6. 字节码执行)
      • [7. 常见问题与调试](#7. 常见问题与调试)
      • [8. 最佳实践](#8. 最佳实践)

Java 虚拟机(JVM, Java Virtual Machine)是 Java 平台的核心组件,它负责执行 Java 字节码。JVM 提供了一个跨平台的运行环境,使得 Java 程序可以在不同的操作系统上运行而无需重新编译。以下是关于 JVM 的一些关键内容:

1. JVM 架构

JVM 主要由以下几个部分组成:

  • 类加载器子系统(Class Loader Subsystem)

    • 引导类加载器(Bootstrap Class Loader) :加载核心 Java 类库(如 java.lang.*)。
    • 扩展类加载器(Extension Class Loader) :加载 Java 扩展库(位于 jre/lib/ext 目录下的类库)。
    • 应用程序类加载器(Application Class Loader):加载用户自定义的应用程序类。
  • 运行时数据区(Runtime Data Area)

    • 方法区(Method Area):存储类的结构信息,如运行时常量池、字段和方法数据、构造函数和普通方法的字节码内容等。
    • 堆(Heap):存储对象实例和数组。堆是所有线程共享的内存区域。
    • 虚拟机栈(VM Stack):每个线程都有一个私有的虚拟机栈,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
    • 本地方法栈(Native Method Stack):与虚拟机栈类似,但为本地方法服务。
    • 程序计数器(Program Counter Register):记录当前线程所执行的字节码指令地址。
  • 执行引擎(Execution Engine)

    • 解释器(Interpreter):逐条解释并执行字节码。
    • 即时编译器(Just-In-Time Compiler, JIT):将热点代码编译成本地机器码,提高执行效率。
    • 垃圾收集器(Garbage Collector, GC):自动管理内存,回收不再使用的对象。
    • 本地接口(Native Interface):与本地方法库交互,调用本地方法。
  • 本地方法库(Native Method Libraries)

    • 包含了特定平台相关的本地方法实现,如文件 I/O、网络通信等。

2. 垃圾收集机制

JVM 的垃圾收集机制主要负责自动管理内存,回收不再使用的对象。常见的垃圾收集算法包括:

  • 标记-清除(Mark and Sweep)

    • 标记阶段:从根集合开始遍历,标记所有可达的对象。
    • 清除阶段:回收未被标记的对象。
  • 复制(Copying)

    • 将存活对象从一个空间复制到另一个空间,然后清空原来的内存空间。
  • 标记-整理(Mark and Compact)

    • 标记阶段:标记所有可达的对象。
    • 整理阶段:将存活对象向一端移动,然后清理边界外的内存。
  • 分代收集(Generational Collection)

    • 将堆分为新生代(Young Generation)和老年代(Old Generation),针对不同代采用不同的收集策略。
    • 新生代通常使用复制算法,老年代通常使用标记-整理或标记-清除算法。

3. 性能优化

  • JIT 编译器

    • 通过将热点代码编译成本地机器码,提高执行效率。
    • 可以通过 -XX:CompileThreshold 参数调整触发 JIT 编译的阈值。
  • 垃圾收集器选择

    • 不同的垃圾收集器适用于不同的场景,如 Serial GC、Parallel GC、CMS GC 和 G1 GC。
    • 可以通过 -XX:+UseSerialGC-XX:+UseParallelGC-XX:+UseConcMarkSweepGC-XX:+UseG1GC 等参数选择合适的垃圾收集器。
  • 堆大小设置

    • 通过 -Xms-Xmx 参数设置初始堆大小和最大堆大小。
    • 合理设置堆大小可以避免频繁的垃圾收集和 OutOfMemoryError。
  • 其他优化参数

    • -XX:NewRatio:设置新生代和老年代的比例。
    • -XX:SurvivorRatio:设置 Eden 区和 Survivor 区的比例。
    • -XX:MaxTenuringThreshold:设置晋升老年代的最大年龄。
    • -XX:ParallelGCThreads:设置并行垃圾收集的线程数。

4. 内存模型

JVM 的内存模型规定了多线程环境下对共享变量的访问规则,主要包括:

  • 主内存与工作内存

    • 每个线程都有自己的工作内存,存储了该线程读写共享变量的副本。
    • 主内存中存储了所有的共享变量。
  • 原子性、可见性和有序性

    • 原子性:保证基本数据类型的读写操作是原子的。
    • 可见性:确保一个线程对共享变量的修改对其他线程是可见的。
    • 有序性:禁止编译器和处理器对指令进行重排序。
  • volatile 关键字

    • 保证变量的可见性和有序性。
    • 防止指令重排序。
  • synchronized 关键字

    • 保证代码块的原子性和可见性。
    • 通过监视器锁(Monitor Lock)实现互斥访问。

5. 类加载过程

类加载过程主要包括以下步骤:

  • 加载(Loading)

    • 通过类的全限定名获取二进制流。
    • 将二进制流转换为方法区内的运行时数据结构。
    • 在内存中生成一个代表这个类的 java.lang.Class 对象。
  • 验证(Verification)

    • 确保被加载的类符合 JVM 规范,防止恶意代码破坏 JVM 安全。
  • 准备(Preparation)

    • 为类的静态变量分配内存,并设置默认初始值。
  • 解析(Resolution)

    • 将符号引用替换为直接引用。
  • 初始化(Initialization)

    • 执行类构造器 <clinit>() 方法,初始化静态变量和静态代码块。

6. 字节码执行

  • 字节码

    • Java 源代码经过编译后生成的中间表示形式。
    • 字节码是一种平台无关的二进制格式。
  • 解释执行

    • 解释器逐条解释并执行字节码。
  • 即时编译

    • JIT 编译器将热点代码编译成本地机器码,提高执行效率。

7. 常见问题与调试

  • OutOfMemoryError

    • 堆内存溢出(Heap Space):增加堆内存大小。
    • 栈内存溢出(Stack Overflow):检查递归调用深度。
    • 方法区内存溢出(PermGen 或 Metaspace):增加方法区大小。
  • 性能监控工具

    • JConsole:图形化监控工具,可以查看 JVM 的内存使用情况、线程状态等。
    • VisualVM:更强大的图形化监控工具,支持性能分析、内存快照等功能。
    • jstat:命令行工具,用于监控 JVM 的性能统计信息。
    • jmap:命令行工具,用于生成堆转储快照。
    • jstack:命令行工具,用于打印线程堆栈跟踪信息。

8. 最佳实践

  • 合理设置堆大小

    • 根据应用的实际需求设置 -Xms-Xmx,避免频繁的垃圾收集。
  • 选择合适的垃圾收集器

    • 根据应用的特点选择适合的垃圾收集器,如低延迟应用可以选择 G1 GC。
  • 减少不必要的对象创建

    • 使用对象池、缓存等技术减少对象的创建和销毁。
  • 使用并发编程

    • 利用多线程提高应用的并发处理能力,但要注意线程安全问题。
  • 定期进行性能分析

    • 使用性能监控工具定期分析应用的性能瓶颈,进行针对性优化。

JVM 是 Java 应用程序运行的基础,理解 JVM 的架构、垃圾收集机制、性能优化、内存模型、类加载过程等内容对于开发高性能、可靠的 Java 应用至关重要。通过合理的配置和最佳实践,可以显著提升应用的性能和稳定性。

精彩专栏推荐订阅:在下方专栏👇🏻
2023年华为OD机试真题(A卷&B卷)+ 面试指导
精选100套 Java 项目案例
面试需要避开的坑(活动)
你找不到的核心代码
带你手撕 Spring
Java 初阶

相关推荐
yaoxtao5 分钟前
java.nio.file.InvalidPathException异常
java·linux·ubuntu
Swift社区1 小时前
从 JDK 1.8 切换到 JDK 21 时遇到 NoProviderFoundException 该如何解决?
java·开发语言
叙白冲冲2 小时前
JVM:程序计数器
jvm
DKPT2 小时前
JVM中如何调优新生代和老生代?
java·jvm·笔记·学习·spring
phltxy2 小时前
JVM——Java虚拟机学习
java·jvm·学习
心想事成的幸运大王3 小时前
JVM如何排查OOM
jvm
seabirdssss4 小时前
使用Spring Boot DevTools快速重启功能
java·spring boot·后端
喂完待续4 小时前
【序列晋升】29 Spring Cloud Task 微服务架构下的轻量级任务调度框架
java·spring·spring cloud·云原生·架构·big data·序列晋升
benben0444 小时前
ReAct模式解读
java·ai