引言

最近在面试的过程中,很多稍微大一点的公司都会问你跟jvm有关的相关知识点,所以就想通过文章的形式将学习jvm的一些经验发表出来,对自己也算是一个复习的效果。
在这里插入图片描述
参考书籍:“深入理解java虚拟机”

虚拟机类加载机制

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

类加载的时机

一个类从被类加载器加载到虚拟机内存中,到卸载出内存中为止,它的整个生命周期会经历加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、使用(Initiallization)、使用(Using)和卸载(Unloading)七个阶段。
在这里插入图片描述
这张图是借鉴网上的,比较清晰的描述了整个类的声明周期。

在上面的过程中对于加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,但是解析过程是不确定的,解析过程有可能会在初始化阶段之后再开始(这里跟方法的动态绑定和静态绑定有关,在以后的篇幅中会详细去说明)

加载(Loading)

我们需要把“加载”和“类加载”区分一下,加载是类加载中的一个过程。jvm在类加载的过程主要完成以下的三件事:

  • 通过类的全限定名去获取定义此类的二进制字节流
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据
  • 在内存中生成一个代表这个类的Class对象,作为方法区这个类的各种数据的入口
类的二进制的获取方式

对于类的二进制数据流,虚拟机可以通过多种途径产生或获取。(只要所读取的字节码符合JVMV规范即可)

  • 虚拟机可能通过文件系统读入一个class后缀的文件(最常见)
  • 读入jar、zip等归档数据包,提取类文件。
  • 事先存放在数据库中的类的二进制数据
  • 使用类似于HTTP之类的协议通过网络进行加载
  • 在运行时生成一段Class的二进制信息等

第一种方式获取二进制字节流可以去看看博主的一篇文章彻底弄懂类加载

数组类的加载

在这个类加载的过程中需要注意一点的是对于数组类来说会有点不同,数组类本身不通过类加载器创建,它是由Java虚拟机直接在内存中动态构造出来的,其中数组类的加载过程:

  1. 如果数组的元素类型是引用类型,那么就遵循定义的加载过程递归加载和创建数组A的元素类型;
  2. JVM使用指定的元素类型和数组维度来创建新的数组类。

如果数组的元素类型是引用类型,数组类的可访问性就由元素类型的可访问性决定。否则数组类的可访问性将被缺省定义为public。

类模板的位置

加载的类在JVM中创建相应的类结构,类结构会存储在方法区(JDK1.8之前:永久代;JDK1.8之后:元空间)

Class实例的位置

类将.class文件加载至元空间后,会在堆中创建一个Java.lang.Class对象,用来封装类位于方法区内的数据结构,改Class对象是在加载类的过程中创建的,每个类都对应有一个Class类型的对象

总结

加载阶段结束之后,java虚拟机外部的二进制字节流就按照虚拟机所设定的格式存储在方法区中了,方法区中的数据存储格式完全是由虚拟机实现定义。类型数据存储在方法区之后,会在java堆内存中实例化一个java.lang.Class类的对象,这个对象将作为程序访问方法区中的类型数据的外部接口。

加载阶段与连接阶段的部分动作是交叉进行的,也就是说的加载阶段还没完成连接阶段可能就已经开始了,但是这些夹在加载阶段之中进行的动作,任然属于加载阶段的一部分,这两个阶段的开始时间仍然是保持着固定的先后循序的。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐