本文咱们来研究一个Java字节码文件(Class文件)是如何加载入内存中的,在這個过程当中涉及类加载过程当中的加载,验证,准备,解析(链接),初始化,使用,销毁过程,并探讨实行这些过程的类加载器,以及其加载的逻辑。java
Java拥有动态加载类和动态链接的特性,所以其加载过程并不像其余语言在编译时就已经完成,它是动态进行的,即在程序运行过程当中动态加载入内存中。数组
在这里须要记住的是,图中的顺序说明的是阶段开始的顺序,并非后面的阶段须要等到前面的执行完成后才可以执行,其在运行过程当中是一个交叉混合执行的过程。安全
此外解析阶段也是一个特殊的阶段,为了支持Java语言的动态绑定,不少时候 Java 只要在运行后才能知道实际调用的对象是什么,所以解析阶段有时是开始在初始化后的。网络
加载阶段完成的是将虚拟机外部的二进制字节流按照虚拟机所需的格式存储在方法区之中。而为了完成这步须要完成哪些功能呢:数据结构
须要注意的是,上面所说的3个步骤,都只是规范要求的部分,这个要求实际上是比较松的,不少东西并无限制的很死,好比说第一步的获取二进制流,其并无要求二进制流必须从Class文件获取,所以在使用过程当中类的二进制流能够从网络获取,能够动态计算生成等等。jvm
验证做用是确保文件的字节流包含信息符合当前虚拟机要求,保证其并不会危害虚拟机的安全。由于之前说过 Class 文件并不都是源码编译而来的,人是能够手动修改生成 Class 文件的,所以这一步验证工做就十分有必要了。那么验证都须要验证哪些地方呢:布局
文件格式验证优化
这一步主要是保证Class文件格式上符合Java信息的要求。例如文件类型,版本号,常量池,常量池数据等等。。。。。。3d
此外在这一步字节流就会进入内存的方法区之中了,后面的操做都是基于方法区内的存储结构进行的。指针
元数据验证
对字节码描述信息进行语义分析,例如类是否有父类,重载是否正确,final,abstract有没有用错等,其主要目的是对类的元数据进行语义分析,保证符合Java语言规范。
字节码验证
对数据流和控制流进行分析。例如字节码指令集的正确,程序跳转的安全。其主要目的是检查方法体内的数据安全,确保程序语义合法,符合逻辑。
符号引用验证
符号引用验证也是一个比较特殊的阶段,其为解析阶段服务(这也验证了前面所说的,这几个过程并非依次执行完成的)。在解析过程当中,虚拟机将符号引用转换为直接引用,其主要是对常量池中的各类符号引用作匹配性校验。检验内容包括如下几个:
为类变量(被static修饰的变量)分配内存并设置类变量初始值。
这里须要注意的是设初始值值得是为其设置零值,例如数值量的 0,boolean 值的 false 等。可是特殊状况下,如类变量是一个常量,那么在准备阶段,虚拟机就会将其设置为常量指代的值。
在验证阶段的符号引用验证说过解析阶段就是将符号引用转换为直接引用,那么符号引用和直接引用分别指什么呢,他们之间又有何区别:
在这一步虚拟机会将类/接口,字段,类方法,接口方法等进行解析,变为直接引用。
初始化阶段主要是初始化类变量和其余资源,主要是经过<clint>()
方法。
<clint>()
是经过编译器自动收集全部类变量的赋值动做和静态语句块(static{}块
)并按照顺序合并生成的。
static块能够为前面未定义的变量赋值,但没法访问
static{ i = 111; // 下面语句没法编译经过,会提示Illegal forward reference // System。out。println(i); } static int i = 0; public static void main(String[] args){ System。out。println(i);` }
程序输出为0,由于其初始化操做是按照顺序进行的,但若是这里static int i;
,不为其赋值,那么结果就是111。
虚拟机并无要求何时进行其余阶段的工做,但初始化阶段不一样。当发生一下几种状况时,虚拟机必需要开始初始化工做。(做为初始化前的加载,验证,准备,解析也就都循序渐进开始了)。
new
(对象都要生成了,确定要初始化了),get/put static
(使用静态变量了,确定要赋值了),invoke static
(调用静态方法了都,确定要为静态量赋值);java。lang。reflect
中的方法对类进行反射调用;虚拟机规定有且仅有以上5种方法须要当即初始化,还有一些调用,看起来像须要初始化,但其实并不须要,能够称之为被动调用。
在本文中着重介绍了一个类加载入内存中的各个阶段过程,了解这个阶段过程能够明白虚拟机是如何将一个静态的类文件,通过一系列的动做变为 Java 内存中的各类数据结构。
在下一篇文章咱们将会介绍执行加载阶段的主体,类加载器,明白类加载器的模型以及其背后的逻辑,并尝试自定义一个类加载器,来完成加载工做。
文章在公众号 "iceWang" 第一手更新,有兴趣的朋友能够关注公众号,第一时间看到笔者分享的各项知识点,谢谢!笔芯!
本系列文章主要借鉴自《深刻分析 JavaWeb 技术内幕》和《深刻理解 Java 虚拟机- JVM 高级特性与最佳实践》。