`

虚拟机类加载机制(二)类加载过程

 
阅读更多



 

 

加载

在加载阶段,虚拟机需要完成以下三件事:

1、通过类的全限定名来获取定义此类的二进制字节流。但规范并没有指明二进制字节流要从一个Class文件中获取,所以,在Java的发展历史中出现了很多字节流的提供方式:zip包,网络(例如applet),动态代理技术,其他文件(如jsp);

2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;

3、在Java堆中生成一个代表这个类的java.lang.Class对象,作为方法区这些数据的访问入口。

 

相对于类加载过程的其他阶段来说,加载阶段(准确的说,是在加载阶段中获取类的二进制字节流的动作)是开发期可控性最强的阶段,既可以使用系统提供的类加载器完成,也可由用户自定义的类加载器来完成。

 

加载阶段与连接阶段的部分内容(如一部分字节码文件格式的验证动作)是交叉进行的,加载动作尚未完成,连接阶段可能已经开始。

 

验证

目的是确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全。

包含以下几个方面的验证工作:

1、文件格式验证;

2、元数据验证(确保不存在不符合Java语言规范的元数据信息存在,比如是否覆盖了父类中被final修饰的属性等);

3、字节码验证。主要是进行数据流和控制流分析;

4、符号引用验证。

 

准备

准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。并且,此时分配的初始值是指该数据类型的零值。假设有一个类变量的定义为

public static int aStaticVariable = 123;

 则在准备阶段过后该变量的初始值为0,而非123,因为此时并没有执行任何Java方法。而把aStaticVariable赋值为123的putstatic指令是在程序被编译后,存放在类的构造器<clinit>()方法之中,所以把aStaticVariable赋值为123的动作将发生在初始化阶段。但如果aStaticVariable是经过final修饰的,那么在准备阶段就会直接将其赋值123。

 

解析

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

符号引用:以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用是能无其一的定位到目标即可。符号引用与虚拟机实现的内存布局无关,引用的目标并不一定已经加载到内存中。

直接引用:可以是直接指向目标的指针、相对偏移量或者是一个能直接定位到目标的句柄。直接引用是虚拟机实现的内存布局相关的,同一个符号引用在不同虚拟机实力上翻译出来的直接引用一般不会相同。如果有了直接引用,说明引用的目标已经存在内存中存在。

 

虚拟机规范并没有规定解析阶段发生的具体时间,只是要求了在执行anewarray, checkcast, getfield, getstatic, instanceof, invokeinterface, invokespecial, invokestatic, invokevirtual, multianewarray, new, putfield和putstatic这13个用于操作符号引用的字节码指令之前,先对它们所使用的符号引用进行解析。

 

虚拟机实现可能会对同一个符号引用的解析结果进行缓存,以提高响应效率。

 

解析动作主要针对类或接口(对应常量池的CONSTANT_Class_info)、字段(CONSTANT_Fieldref_info)、类方法(CONSTANT_Methodref_info)及接口方法(CONSTANT_InterfaceMethodref_info)四类符号引用进行。

 

 

初始化

类的初始化阶段是类加载过程的最后一步。到了初始化阶段,才真正开始执行类中定义的Java程序代码(或者说是字节码)。

前面提到,在准备阶段,虚拟机已经为变量赋值过一次初始值(初始零值,如果是经过final修饰,则直接按照代码赋值),而在初始化阶段,则是根据程序的定义进行类变量和static语句块的初始化工作。换做更专业的说法,类的初始化阶段是执行类构造器<clinit>()方法的过程。

  • <clinit>()方法是由编译器自动收集类中所有类变量的赋值动作和静态语句块(static{})块中的语句合并产生的。编译器收集的顺序一定是先变量赋值,再静态语句块(无论两者在源文件中出现的顺序如何),因此,在静态语句块中可以访问到类变量的初始值。
  • <clinit>()方法与类的构造函数(或者说实例构造器<init>())方法不同,它不需要显式调用父类构造器,虚拟机会保证在子类的<clinit>()方法执行之前,父类的<clinit>()方法已经执行完毕。因此,在虚拟机中第一个被执行的<clinit>()方法的类一定是java.lang.Object。
  • 由于父类的<clinit>()方法先于子类执行,所以父类中的静态语句块要优先于子类的变量赋值操作。
  • <clinit>()方法并不是必须的,如果类或接口中没有类变量的赋值或者静态语句块,则编译器可以不为这个类生成<clinit>()方法。
  • 接口中不能使用静态语句块,但可以有静态变量,因此接口和类一样都会生成<clinit>()方法。但不同的是接口中的<clinit>()不需要先执行父接口的<clinit>(),只有当父接口中定义的变量被使用时,父接口才会被初始化。另外,接口的实现类在初始化时也一样不会执行接口的<clinit>()方法。
  • 虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确的加锁同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程被阻塞。所以,如果在<clinit>()方法中存在耗时操作,会形成很隐蔽的阻塞。

 

 

 

 

 

  • 大小: 53.7 KB
分享到:
评论

相关推荐

    虚拟机类加载机制

    经典的java虚拟机类加载机制 看完后会有醍醐灌顶的感觉

    Dalvik虚拟机类加载机制分析图

    作者:【郭孝星】http://blog.csdn.net/allenwells 微博:【郭孝星的新浪微博】http://weibo.com/allenwells 邮箱:allenwells@163.com 博客:http://blog.csdn.net/allenwells Github:...

    什么是虚拟机类加载机制以及加载过程,以及类加载时机.xmind

    什么是虚拟机类加载机制以及加载过程,以及类加载时机

    Java虚拟机类加载机制及双亲委派模型

    Java虚拟机类加载机制及双亲委派模型

    深入理解Java虚拟机-虚拟机类加载机制.xmind

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

    Java虚拟机类加载机制浅谈

     虚拟机将描述类的数据从Class文件加载到内存,并对数据进行校验、准备、解析和初始化,终会形成可以被虚拟机使用的Java类型,这是一个虚拟机的类加载机制。Java中的类是动态加载的,只有在运行期间使用到该类的...

    虚拟机类加载机制.mmap

    思维导图

    Java虚拟机类加载机制?案例分析

    在《Java虚拟机类加载机制》一文中详细阐述了类加载的过程,并举了几个例子进行了简要分析,在文章的后留了一个悬念给各位,这里来揭开这个悬念。建议先看完《Java虚拟机类加载机制》这篇再来看这个,印象会比较深刻...

    ClassLoader类加载机制

    类加载器是 Java 语言的一个创新,也是 ...不过如果遇到了需要与类加载器进行交互的情况,而对类加载器的机制又不是很了解的话,就很容易花大量的时间去调试 ClassNotFoundException和 NoClassDefFoundError等异常。

    12.虚拟机的加载机制1

    1. 加载 2. 验证 【连接】 3. 准备 【连接】 4. 解析 【连接】 5. 初始化 6. 使 7. 卸载 1. 遇到new、getstatic、puts

    Java类加载原理解析

    Java的类加载机制是java技术体系中比较核心的部分,虽然和大部分开发人员直接打交道不多,但是对其背后的机理有一定理解有助于排查程序中出现的类加载失败等技术问题,对理解java虚拟机的连接模型和java语言的动态性...

    深入理解java类加载机制

    此外,我们还会探讨Java程序的类加载器和双亲委派机制,以及自定义类加载器和类卸载的实现原理和应用方法。 总的来说,本资源将为Java程序员提供全面的Java字节码和类加载原理和实践经验。通过学习本资源,开发人员将...

    JVM类加载机制详细讲解

    讲解JVM的ClassLoader子系统原理.

    JAVA虚拟机的类装载机制的原理分析与应用研究.pdf

    详细描述java虚拟机内部加载类机制和原理

    Java虚拟机之类加载机制

    后在运行的时候,虚拟机把描述类的信息从class文件加载到内存,然后再进行校验、解析和初始化等过程,后形成可以被java虚拟机“读懂”的java类型。那么从class——&gt;java虚拟机能“读懂”的java类型是本文要讲解的...

    虚拟机中类加载机制

    1、为什么要了解虚拟机的类加载机制? public class SSClass { static { System.out.println(SSClass init!); } } public class SuperClass extends SSClass { static { System.out.println(SuperClass init!...

    详解JAVA类加载机制(推荐)

    JAVA源码编译由三个过程组成: 1、源码编译机制。 2、类加载机制 ...系统可能在第一次使用某个类时加载该类,也可能采用预加载机制来加载某个类,当运行某个java程序时,会启动一个java虚拟机进程,两次运行

    JVM 运行时数据区域,垃圾回收机制,类加载机制三大功能详解.docx

    VM相关的一些内容,比如下面的这三个内容算是比较核心知识点了 运行时数据区域: 在运行时数据区里存储类Class文件元数据...类加载机制: 虚拟机首先需要把编译完成的字节码文件通过类加载器来加载到运行时数据区域

    类加载机制1

    简介类加载器是Java语言的一个创新,也是Java语言流行的重要原因之一。它使得 Java 类可以被动态加载到 Java 虚拟机中并执行。类加载器从 JDK 1

Global site tag (gtag.js) - Google Analytics