三个主要阶段:加载、连接(验证、准备、解析)、初始化
1. 加载
将字节码从不同的数据源(class文件、jar包、网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象。此过程由类加载器完成。
2. 连接
2.1 验证:
- 目地是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
- 包括:文件格式验证(是否以魔数oxcafebabe开头)、元数据验证、字节码验证和符号引用验证
- 可以考虑使用
-Xverify:none
参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间
2.2 准备:
JVM会再该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始值,如0、0L、null、false等)。这些变量所使用的内存都将在方法区中进行分配
2.3 解析:
虚拟机将常量池内的符号引用替换为直接引用的过程
3. 初始化
- 到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行<clinit>()方法的过程。
- <clinit>()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并
- 虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时区初始化一个类,那么只会有一个线程区执行这个类的<clinit>()方法,其它线程都需要阻塞等待,知道活动线程执行<clinit>()方法完毕