参考链接:一篇文章彻底理解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、类的双亲委派与打破双亲委派
加载器有是四类
- 根加载器
- 扩展加载器
- 应用加载器
- 自定义加载器,不应需要使用。
自定义加载器的一般使用场景:
- 加载非标准来源的类:例如从网络、数据库、加密文件或其他非文件系统的来源加载类。
- 实现类的隔离:例如在应用服务器中,不同的Web应用可能需要使用相同类的不同版本,通过自定义类加载器可以实现类隔离。
3.热部署:在不重启JVM的情况下,重新加载修改过的类,实现动态更新。 - 代码加密:加载经过加密的类文件,在自定义类加载器中解密,保护源代码。
- 绕过双亲委派模型:根据特定需求改变类的加载顺序,例如Java的SPI机制。
- 动态生成类:例如通过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 去执行














网友评论