Class文件的装载流程

  只有被Java虚拟机装载的Class类型才能在程序中使用。

  Class文件装载过程:

    

java虚拟机错误 java虚拟机无法载入_初始化

  类装载的条件

    Class只有在必须使用的时候才会被装载,Java虚拟机不会无条件地装载Class类型。Java虚拟机规定,一个类或接口在初次使用前,必须要进行初始化。“使用”指主动使用。

  加载类

    在加载类时,Java虚拟机完成:

    1、通过类的全名,获取类的二进制数据流。

    2、解析类的二进制数据流为方法区内的数据结构

    3、创建java.lang.Class类的实例,表示该类型

  虚拟机可以通过文件系统读入一个Class后缀文件,或者jar,zip等归档数据包。在获取到类的二进制信息后,java虚拟机就会处理这些数据,并最终转为一个java.lang.Class的实例,

  java.lang.Class实例是访问类型元数据的接口,也是实现反射的关键数据,通过Class类提高的接口,可以访问一个类型的方法、字段和信息。

  验证类

    当类加载到系统后,

      

java虚拟机错误 java虚拟机无法载入_Java_02

  准备

    java虚拟机为各类型变量默认的初始值。

    

java虚拟机错误 java虚拟机无法载入_Java_03

    注:java并不支持boolean型,内部实现为int,由于int默认是0,故boolean默认就是false

  解析类

    解析阶段的工作,将类、接口、字段和方法的符号引用转为直接引用。  

    以字节码调用了System.out.println()为例:

    

java虚拟机错误 java虚拟机无法载入_java_04

  初始化

    如果前面都没有问题,类开始执行Java字节码。初始化阶段的重要工作是执行类的初始化方法<clinit>。方法<clinit>是由编译器自动生成的,它是由类静态成员的赋值语句以及static语句块合并产生的。

    如果一个类没有赋值语句,也没有static语句块,那么生成的<clinit>函数就应该是空,因此,编译器就不会为该类插入<clinit>函数。

    对于<clinit>函数的调用,也就是类的初始化,虚拟机会在内部确保其多线程环境的安全性,也就是说,当多个线程试图初始化同一个类时,只有一个线程可以进入<clinit>函数,而其他线程必须等待,

    如果之前线程已经初始化好了,直接返回给它已经准备好的信息。

    正因为函数<clinit>是线程安全的,因此,在多线程环境下进行类初始化时,可能会引起死锁,并且这种死锁很难发现,因此看起来没有死锁一样。可以通过对堆Dump的分析解决。