jvm性能调优

java基础知识,JVM虚拟机类加载机制

2020-02-15  本文已影响0人  javap

知识要点:

类加载机制简介
类加载机制流程

类加载机制简介

虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。

类加载机制流程

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)7个阶段。其中准备、验证、解析3个部分统称为连接(Linking)



类加载的过程包括了加载、验证、准备、解析、初始化五个阶段。在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持 Java 语言的运行时绑定(也成为动态绑定或晚期绑定)。另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。

加载

加载是类加载过程的第一个阶段,在加载阶段,虚拟机需要完成以下三件事情:
①获取二进制字节流
②静态存储结构转化为方法区的运行时数据结构
③在Java堆里面生成一个类对象,作为方法区的访问入口。
Java二进制字节流可以获取的途径有:

验证

验证是连接阶段的第一步,确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。验证阶段大致分下面4个动作:

文件格式验证

验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理。

元数据验证

该阶段主要对字节码描述的信息进行语义分析,以保证符合Java语言规范要求。

字节码验证
符号引用验证
准备

准备阶段是为类变量分配内存并设置类变量初始化的阶段,这些变量所使用的内存当将在方法区中进行分
配。只对类变量进行内存分配(static修饰),不包括实例变量,实例变量将会在对象实例化是随着对象一起分配在Java堆中。
如:一个类变量的定义为

// n的初始化值是0,而不是2。因为这个时候还没执行任何初始化方法(<clinit>)。
public static int n = 2;

再例如:

// 编译时会为m生成ConstantValue属性,在准备阶段会根据ConstantValue将m值设置为2
public static final int m = 2;

类变量和实例变量

class A extends B implements C, D{
    private String str; //字段的解析
}

解析字段的顺序:
①先查找本类A,如果包含了简单名称和字段描述符都与目标相匹配的字段,则返回这个字段的直接引用,查找结束。
②否则,在接口中查找。将会按照集成关系从下往上递归搜搜各个接口和它的父接口,如果接口中包含了简单名称和字段描述符都于目标相匹配的字段,则返回这个字段的直接引用,查找结束。
③否则,在父类中查找,如果在父类中包含了简单名称和字段描述符都于目标相匹配的字段,则返回这个字段的直接引用,查找结束
④否则,查找失败,抛出java.lang.NoSuchFieldError异常。
类方法的解析

class A extends B implements C, D{
    private void inc(); //方法的解析
}

①如果在类方法表中发现class_index中索引的A是一个接口,哪就直接抛出java.lang.IncompatiableClassChangeError异常。
②如果通过了第一步,先查找本类A,是否由简单名称和描述符都于目标相匹配的方法,如果有则返回方法的直接引用,查找结束。
③否则,父亲中递归查找是否又简单名称和描述符都与目标相匹配的方法,如果有则返回这个方法的直接引用,查找结束。
④否则,在类实现的接口列表及它们的父接口之中查找是否有简单名名称和描述符都与目标相匹配的方法,如果存在匹配的方法,说明类C是一个抽象类,这时查找结束,抛出java.lang.AbastractMethodError异常。
⑤否则,宣告方法查找失败,抛出java.lang.NoSuchMethodError。
接口方法的解析
与类的方法解析不同,如果在接口方法表中发现class_index中的索引A是个类而不是接口,那就直接抛出java.lang.IncompatiableClassError异常。
否则,先查找本接口,是否有简单名称和描述符都与目标匹配的方法,如果有则返回这个方法的直接引用,查找结束。
否则,在接口的父接口中递归查找,直到java.lang.Object类(查找范围包括Object类)为止,看是否有简单名称和描述符都与目标相匹配的方法,如果有则返回这个方法的直接引用,查找结束。
否则,宣告方法查找失败,抛出java.lang.NoSuchMethodError异常。

初始化

<clinit> 类的初始化。静态变量,静态块的初始化。所有的类变量初始化语句和类型的静态初始化器。
Java在编译之后会在字节码文件中生成<clinit>方法,称之为类构造器,类构造器同实例构造器一样,也会对静态语句块,静态变量进行初始化
<init> 对象的初始化
Java在编译之后会在字节码文件中生成<init>方法,称之为实例构造器。该实例构造器会对语句块,变量进行初始化,并调用父类的构造器。
<clinit>方法是在类加载过程中执行的,而<init>是在对象实例化执行的,所以<clinit>一定比<init>先执行。所以整个顺序就是:

上一篇 下一篇

猜你喜欢

热点阅读