JVM性能调优
- 1. 类加载的运行全过程
- 1.1 加载
- 1.2 验证
- 1.3 准备
- 1.4 解析
本文是按照自己的理解进行笔记总结,如有不正确的地方,还望大佬多多指点纠正,勿喷。
课程内容:
1、从java.exe开始讲透Java类加载运行全过程
2、从JDK源码级别剖析JVM核心类加载器
3、从JDK源码级别剖析类加载双亲委派机制
4、手写自定义类加载器打破双亲委派机制
5、Tomcat类加载机制深度剖析
6、手写Tomcat类加载器实现多版本代码共存隔离
1. 类加载的运行全过程
当我们用java命令运行某个类的main函数的启动程序时,首先需要通过类加载器把主类加载到JVM中。
public class Math {
public static final int initData = 666;
public static User user = new User();
public int compute() { //一个方法对应一块栈帧内存区域
int a = 1;
int b = 2;
int c = (a + b) * 10;
return c;
}
public static void main(String[] args) {
Math math = new Math();
math.compute();
}
}
通过Java命令执行代码的类加载全过程
其中loadClass的类加载过程有以下几步:
加载 >> 验证 >> 准备 >> 解析 >> 初始化 >> 使用 >> 卸载
- 加载:在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用类的main()方法,new对象等,在加载阶段会在内存区域生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
- 验证:校验字节码文件的准确性;
- 准备:给类的静态变量分配内存,并赋予默认值;
- 解析:将符号引用替换为直接引用,该阶段会把一些静态方法替换为只想数据所在内存区域的指针或句柄(直接引用),这是所谓的静态链接过程,动态链接是在程序运行过程完成的将符号引用替换为直接引用;
- 初始化:对类的静态变量初始化为指定的值,执行静态代码块;
1.1 加载
在加载阶段,虚拟机需要完成以下三件事情:
- 通过类的全限定名来获取定义此类的二进制文件流;
- 将这个字节流所代表的静态存储结构转化为方法区的运行时结构
- 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口;
《Java虚拟机规范》对这三点的要求并不是特别具体,所以留给虚拟机实现与Java应用的灵活度非常大,例如我们通过一个类的全限定类名来获取定义此类的二进制字节流这条规则,它并没有指明二进制文件流必须得从某个Class文件中获取,确切的说根本没有指明说要从哪里获取,如何获取。这也是日后的JAR、WAR、EAR格式的基础。
这一阶段就是先把字节码文件丢到内存。但是加载之前要先验证一下。
1.2 验证
验证是连接的第一步,这一个阶段的目的是保证Class文件的字节流中包含的信息符合<JVM虚拟机规范>的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。验证阶段大致上会完成下面四个阶段的校验动作:
- 文件格式验证:这个阶段要验证字节流文件是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理。例如:是否以魔数0xCAFEBABE开头,主次版本是否在当前Java虚拟机的接受范围之内等;
- 元数据验证:这个阶段主要是对字节码描述的信息进行语义分析,以确保其描述信息符合<Java语言规范>的要求,例如:这个类是否有父类,这个类是否继承了不允许继承的类(被final修饰的类)等;
- 字节码验证:这个阶段验证过程是最复杂的一个过程,主要目的是通过数据流分析和控制流分析,确定程序语义是合法的、符合逻辑的。在第二个阶段对元数据信息中的数据类型校验分析完毕后,这阶段就要对类的方法体进行校验分析,保证被校验类的方法在运行时不会做出危害虚拟机的行为。
- 符号引用验证:最后一个阶段校验行为发生在虚拟机将符号引用转换为直接引用的时候,这个转化动作在链接阶段的第三阶段-解析阶段中发生。符号引用验证可以看作是对类自身以外的各类信息进行匹配校验,通俗来说就是,该类是否缺少或被禁止访问它依赖的某些类、方法、字段等资源。
1.3 准备
准备之前要先验证各种格式等是否正确。准备就是把静态变量初始值赋值。这个赋值与最终值没有关系,比如Boolean就会赋值false,int就先赋值为0这种。
1.4 解析
解析阶段是将Java虚拟机将常量池内的符号引用替换直接引用的过程。
- 符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能够无歧义地定位到目标即可。
- 直接引用:直接引用是可以直接指向目标的指针、相对偏移量或者是一个能简介定位到目标的句柄。