JVM组成

作者: 后知不觉1 | 来源:发表于2025-10-14 09:38 被阅读0次

参考链接:一篇文章彻底理解JVM的组成,各组件的底层实现逻辑

1. Java虚拟机(JVM)核心组件有

  • 类加载器
  • 运行时数据区
  • 执行引擎
  • 本地方法接口


    image.png

2.classloader

classloader,主要是将java字节码文件(.class文件)加载到jvm内存中
主要作用

  • 加载:从文件系统或者网络中读取字节码文件
  • 链接:验证字节码的合法性,分配内存并设置类变量的初始值
  • 初始化赋值:执行静态初始化块和静态变量赋值

2.1、加载

java -Xms3G -Xmx3G -Xmn2G -Xss256K  -cp /opt/asd-ctrl.jar:/opt/lib/* com.springboot.PortalCtrlApp

比如上述命令时,首先会将-cp指定的jar 全部读取转换成java 字节码,读取到内存中;以便后续处理

2.1、链接

  • 验证阶段:确保加载字节码符合规范;检查内容
  • 准备阶段:为静态变量分配内存并设置初始值
  • 解析阶段:将符号应用转换为直接引用;将符号应用转换为地址引用

2.3、初始化

  • 链接完成后执行,执行类的静态代码块;此时开发者已经可以做一些特定动作

2.4、类的双亲委派与打破双亲委派

加载器有是四类

  • 根加载器
  • 扩展加载器
  • 应用加载器
  • 自定义加载器,不应需要使用。

自定义加载器的一般使用场景:

  1. 加载非标准来源的类:例如从网络、数据库、加密文件或其他非文件系统的来源加载类。
  2. 实现类的隔离:例如在应用服务器中,不同的Web应用可能需要使用相同类的不同版本,通过自定义类加载器可以实现类隔离。
    3.热部署:在不重启JVM的情况下,重新加载修改过的类,实现动态更新。
  3. 代码加密:加载经过加密的类文件,在自定义类加载器中解密,保护源代码。
  4. 绕过双亲委派模型:根据特定需求改变类的加载顺序,例如Java的SPI机制。
  5. 动态生成类:例如通过ASM等字节码工具动态生成类,然后通过自定义类加载器加载。

这里重点说下类的双亲委派
默认加载顺序是先有跟加载器加载java 核心类库,在有扩展加载器加载ext等jar,再有应用加载器加载应用相关jar

如果不按照这个顺序就叫打破双亲委派机制;
能实行多版本插件的版本隔离;
参考地址java classloader说明

3、执行引擎

执行引擎主要组成

  • 解释器: 逐行解释字节码并执行,适合快速启动,但效率低
  • 即时编译器:将热点代码(经常执行的代码)编译为机器码,提高执行效率。编译后代码存放在内存中,供后续调用
  • 垃圾回收器:负责自动管理内存,回收不在使用的对象,防止内存泄漏
# 启动参数强制使用解释器
java -Xint -jar myapp.jar

# 启动参数强制使用即时编译器
java -Xcomp -jar myapp.jar

# 混合模式
java -jar myapp.jar

在解释器与即时编译器选择时,java有一套自己的机制选择;会针对热点方法,热点代码进行选择

4、运行时数据区

运行时数据区也叫jvm内存模型

  • 方法区(永久代): 存储类信息,常量,静态变量等
  • 堆:存储对象实例、数组;是所有线程共享的
  • java 虚拟机栈:每个线程都有的独立栈,用于存放局部变量,方法调用等
  • 程序计数器:只是当前执行的字节码指令位置,当现线程切换是,程序计数器的值可以帮助恢复执行状态。不是计数的
  • 本地方法栈:本地方法调用使用的内存空间,用于存放本地方法参数和局部变量

在1.8 jdk中
方法区被元空间与堆内存取代

  • 元空间:存放类的元数据
  • 堆:静态变量,常量池,对象,数组

参数设置

  • -XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。
  • -XX:MaxMetaspaceSize,最大空间,默认是没有限制的。如果没有使用该参数来设置类的元数据的大小,其最大可利用空间是整个

5、本地接口

功能:允许java代码调用其他语言编写的本地方法;

  • 与底层系统交互:一些操作系统级别的任务,如内存管理、文件系统操作、硬件访问等,Java 本身并不直接支持,因为 Java 是跨平台的,不依赖于特定的操作系统或硬件。通过使用 native 方法,可以绕过 Java 的跨平台限制,直接调用底层系统的原生功能。例如,操作系统提供的特定 API、底层的驱动程序,或硬件接口都可能需要使用 native 代码来实现。

  • 性能优化:一些计算密集型或性能要求极高的任务,Java 可能无法以足够高效的方式来实现。在这种情况下,开发者可能会选择将这些性能关键部分使用 C 或 C++ 等语言实现,并通过 JNI(Java Native Interface)来与 Java 代码进行交互,从而获得更好的性能

可以自定义本地方法进行调用

6、java文件在jvm处理过程

image.png

1.java文件,通过java源码编译器,Java 源代码经过编译后生成 `.class文件,存储的是字节码(二进制数据)。

2.类加载器将字节码数据读到元空间中,并在堆中创建一个java.lang.Class对象,用来封装类在方法区内的数据结构

3.而字节码文件只是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行

4.在某些情况下,执行过程中需要调用本地库(Native Interface)来实现特定功能。

整体流程总结:
.java文件通过java源码编译器进行编译为.class文件,存储的是字节码(二进制数据),类加载器,通过验证、准备、解析、初始化流程、将字节码数据读到方法区中,并在堆中创建一个java.lang.Class对象,用来封装类在方法区内的数据结构,通过编译器,将字节码翻译成底层系统指令,再交由 CPU 去执行

相关文章

网友评论

      本文标题:JVM组成

      本文链接:https://www.haomeiwen.com/subject/dzybtstx.html