jvm类加载机制简介

我们都知道Java里的class文件在编译后产生class文件,这些class文件是编译后的字节码,jvm可以加载并运行这些字节码,这也是为什么Java会被称作一次编译,多处运行,因为字节码是平台无关的。

那么jvm是如何加载这些class文件的?

 虚拟机把描述类的数据从class文件中加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。在Java语言里,类型的加载,链接和初始化过程都是在程序运行期间完成的。

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载,验证,准备,解析,初始化,使用和卸载这七个阶段。其中验证,准备,解析这三个部分统称为连接。

什么情况下开始加载阶段?

对于加载阶段,Java虚拟机规范并没有进行强制约束,各个虚拟机可以自行设定,但是对于初始化阶段,碰到下面五种情况时,必须进行初始化,由于初始化在加载阶段后,所以大概可以人为,碰到以下五种情况,jvm必须要去加载类:

1.碰到new,getstatic,putstatic,invokestatic这四条字节指令时,如果类没有初始化,则需要初始化。这四条指令对应的基本场景是:使用new创建对象时;读取或设置一个类的静态字段时;调用一个类的静态方法时。

2.使用反射对类进行调用时。

3.初始化一个类时,如果发现他的父类还未初始化,则需要先出发父类。

4.当虚拟机启动时,用户需要指定一个主类,虚拟机会先初始化该类。

5.当使用JDK1.7的动态语言支持时,如果MethHandle实例最后的解析结果REF_getStatic,REF_invokeStatic,REF_putStatic的方法句柄,并且这个句柄对应的类没初始化,则需要先初始化。(啥玩意?)

需要注意的是,对于一个接口来说,上面的第三种情况需要改为,在一个接口初始化时,不需要其父类都初始化,只有在正在用到父接口时才会初始化。

下面说一下加载过程的前五个阶段:加载,验证,准备,解析,初始化。

首先,加载过程做了什么?

1.通过一个类的全限定名来获取定义此类的二进制字节流。(显而易见,需要先找到加载的东西)。

2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。(在之前的文章中有说过,类信息是放在方法区的。)

3.在内存中生成一个代表这个类的java.lang.class对象,作为方法区这个类的各种数据访问入口。

对于第一个步骤,并没有规定死一定是要通过class文件来获取字节流的,任何方式都可以,这为以后的动态代理技术奠定了基础。

验证阶段做了什么?

验证是连接阶段的第一步,这个阶段目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。 这里要说明一下,加载和验证的操作虽然在开始时间上是加载=》验证,但是并不是加载完成后才开始验证,而是加载了一部分之后就开始验证操作。要不然,全部加载了才发现验证不通过,不就亏大了。

那么需要做哪些验证呢?

验证阶段的工作量其实是很大的,因为需要验证的东西太多了,虚拟机规范中使用了130页来描述验证的规范。验证阶段大致可以分成四个检验动作:文件格式验证,元数据验证,字节码验证,符号引用验证,每一种验证都有很多项,下面对每一个验证列举几项来大致看一下:

文件验证:

验证字节流是否符合class文件格式规范。

如:是否以魔数0XCAFEBABE开头。主次版本号是否在当前虚拟机处理范围之内。

元数据验证:

对字节码描述信息进行语义分析。

如:该类是否有父类,该类的父类是否集成了不允许被集成的类(final修饰的类)。

字节码验证:

这个阶段是最复杂的,通过数据流和控制流来分析程序语义是否合法,符合逻辑的。

如:保证跳转指令不会跳转到方法体以外的字节码指令上,保证方法体中的类型转换是有效的。

符号引用验证:

这一阶段发生在虚拟机将符号引用转化为直接引用的时候。

如:符号引用中通过字符串描述的全限定名是否可以找到对应的类;指定类是否存在符合方法的字段描述符以及简单名称所描述的方法和字段。

在验证阶段结束之后,就说明当前的class字节流是完全安全可用的了,就可以着手准备使用了。

准备阶段做了什么?

准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中分配。,这个时候分配的只有类变量(static静态的),不包括实例变量。准备阶段结束后类变量的值都为自身类型的零值,因为还没有进行初始化。

解析阶段做了什么?

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。

什么是符号引用和直接引用?

符号引用:符号引用以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义的定位到目标即可。

直接引用:直接引用可以是直接指向目标的指针,相对偏移量,或者一个能简介指向目标的句柄。

知道这俩个概念之后大概就了解到了,解析阶段就是把所有的字面引用的值,转成虚拟机可以使用的指针。

主要有一下几类引用需要解析:

1.类或者接口解析。

2.字段解析。

3.类方法解析。

4.接口方法解析。

最后一个阶段为初始化:初始化阶段将按照原代码中的语义来为变量赋值。

至此,类的加载过程已经完成了。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值