JVM类加载(2)—连接

2、连接

连接就是将已经加载到内存中的类的二进制数据合并到Java虚拟机的运行时环境中去,加载阶段尚未完成,连接阶段可能已经开始。连接阶段包含验证、准备、解析过程。

2.1、验证

验证.class文件正确性,验证阶段大致会完成下面4个阶段的检验动作

(1)、文件格式验证,这一阶段主要验证字节流是否符合Class文件的格式规范,并且能被当前版本的虚拟机处理。

(2)、元数据验证,第二阶段是对字节码描述信息进行语义分析,以保证其描述的信息符合Java语言规范的要求,这个阶段可能包含的验证点如下:

  • 这个类是否有父类(除java.lang.Object类之外,其他所有类都应该有父类)
  • 这个类的父类是否继承了不允许被继承的类(被final关键字修饰的类)
  • 如果这个类不是抽象类,是否实现了其父类或接口之中要求实现的所有方法
  • 类中的变量、方法是否与父类产生冲突(如覆盖了父类的final属性,或者出现不符合规则的方法重载)等

第二阶段主要目的是对类的元数据信息进行语义校验,保证不存在不符合Java语言规范的元数据信息。

(3)、字节码验证,第三阶段是整个验证过程中最复杂的一个阶段,主要目的是通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。在第二阶段对元数据信息中的数据做完验证后,这个阶段将对类的方法体进行校验分析,保证被校验类的方法在运行时不会做出危害JVM安全的事件,例如:

  • 保证任意时刻操作数栈的数据类型与指令代码序列能配合工作,例如不会出现类似这样的情况:在操作栈放置了一个int型的数据,使用时却按照long类型加载入本地变量表中。
  • 保证跳转指令不会跳转到方法体以为的字节码指令上。
  • 保证方法体中的类型转换是有效的。等

(4)、符号引用验证,最后一个阶段的校验发生在虚拟机将符号引用转化为直接引用的时候,这个转化动作将在连接的第三阶段——解析阶段中发生。符号引用验证可以看做是对类自身以外(常量池中的各种符号引用)的信息进行匹配性校验,通常需要校验以下内容:

  • 符号引用中是否能通过字符串描述的全限定名找到对应的类
  • 在指定类中是否存在符合方法描述的字段描述符以及简单名称所描述的方法和字段
  • 符号引用中的类、字段、方法的访问性(private、default、protected、public)是否可被当前类访问。等

2.2、准备

为类的静态变量分配内存,并初始化默认值,就像下面的这行代码,在准备阶段JVM给int变量i分配内存空间,并将i初始化为int型的默认值,在准备阶段时i=0。

private static int i = 1;

2.3、解析

解析阶段JVM会把类中的符号引用转换为直接引用,如下代码,Test类中的showA()方法中调用了类A的print()方法,这里a.print()就是符号引用,在解析阶段会把a.print()体会为方法区中一个指向A类的print()方法在方法区中内存地址的指针,而这个指针就是直接引用

 1 class A{
 2     class A {
 3         public void print() {
 4             System.out.println("this is a");
 5         }
 6     }
 7 
 8     public class Test {
 9         public void showA(A a) {
10             a.print();
11         }
12     }

 

符号引用(Symbolic References):符号引用是以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义的定位到目标即可。符号引用于虚拟机实现的内存布局无关,引用的目标不一定已经加载到内存中。各种虚拟机实现的内存可以各不相同,但是它们所接受的符号引用必须是一致的,因为符号引用的字面量形式明确定义在Java虚拟机规范的Class文件格式中。

直接引用(Direct References):直接引用可以是指向目标地址的指针、相对偏移量或是一个能间接定位到目标的句柄。直接引用是和虚拟机实现的内存布局是相关的,同一个符号引用在不同的虚拟机中翻译出来的直接引用一般是不同的,如果有了直接引用,那引用目标一定已经在内存中了。

posted @ 2017-05-07 20:46  七夜·雪  阅读(329)  评论(0编辑  收藏  举报