继上一篇JVM学习之路3-GC机制和GC收集器分析介绍完垃圾回收相关内容后,这篇说说类的加载机制。咱们平时在写代码的时候更多的是和对象打交道,不多去关心类的相关信息是怎么来的,在以前的系列文章中咱们介绍过类信息是存放在哪的、对象是如何找到本身的类等内容,都没有详细介绍过类是如何来的,它是怎么被加载到虚拟机里的。
知识点
一、类文件结构
二、虚拟机加载类机制java
这里整理了一幅图先作总体展现
上面图已经对各个结构作了简单的说明,字段表集合是不包含方法的局部变量,这里再介绍一下常量池。segmentfault
就是指字面量和符号引用,字面量即java语言层的常量概念,符号引用如:类和接口全限定名、字段方法名称和描述符等。每种常量项都有本身的一个表结构,具体能够再看一下书里的表,这里再也不作引用。通常java用Constant_utf8_info项来存类名和方法名,因此咱们平时定义类和方法的时候不能过长(65535),固然通常也不会那么长。数组
一个类从加载进虚拟机内存到从内存中卸载,整个生命周期以下:
加载、验证、准备、初始化、卸载这五个阶段的顺序是肯定的,如下6种状况下必须先对类进行初始化:
一、遇到new、getstatic、putstatic、invokestatic指令,基本上就是new对象、静态方法调用和静态字段访问。
二、反射调用。
三、父类没初始化过先作初始化。
四、虚拟机启动时执行主类要先初始化。
五、动态语言最终对应的方法静态调用须要先初始化。
六、有默认方法的接口要在类实例化前进行初始化。安全
此阶段把类从文件的二进制流转换到方法区的运行时数据结构并生成class对象。除了从.class文件中加载类信息,咱们还能够经过网络、zip等压缩包、或者在代码中动态生成类信息。这里须要注意的是:数组类不是由类加载器加载,数组类若是放的是引用类型,该引用类型是由类加载器来加载,该数组类会被标识在该类加载器的类名称空间上,若是数组类放的不是引用类型,则会被标识在引导类加载器上。网络
这是链接的第一个阶段,主要是为了保证加载的类字节流符合虚拟机规范,防止恶意代码的侵入,保护虚拟机的安全,为何说java是类型安全的,这部分就是主要缘由,主要有以下几部分校验:
一、文件格式校验,好比文件的魔数是否符合定义。
二、元数据校验,对字节码描述的信息进行校验(看字节码:javap -verbose xxxClass),好比是否继承了不被容许继承的类。
三、字节码验证,经过数据流和控制流分析来确保语义是合法的、符合逻辑的。
四、符合引用验证,发生在虚拟机将符号引用转换为直接引用时,好比检查是否缺乏依赖的外部方法、类等资源。数据结构
正式为类中的变量分配内存和设置初始值。举个例子:布局
public static int value = 123;
如上代码,在准备阶段的时候会将value设置为0,而不是123,真正赋值123是在初始化阶段。固然若是是常量(用final修饰),则会直接初始化为123。学习
将常量池中符号引用替换为直接引用的过程,包括类/接口解析、方法解析、字段解析、接口方法解析等。
符号引用:就是一个字面量,好比类的全限定名,只要能惟一识别该类就行,和内存布局无关。
直接引用:和内存布局相关,内存中要已经存在该目标,直接引用至关于直接定位到该目标。spa
类加载过程的最后一个步骤,虚拟机将主导权交给应用程序。准备阶段在分配内存和设置初始值以后,初始化阶段就会真正设置咱们赋予的初始值,就是在执行类构造器<clinit>()方法的过程。静态语句块中只能访问 到定义在静态语句块以前的变量,定义在它以后的变量,在前面的静态语句块能够赋值,可是不能访问。code
在上面的加载机制中提到了类加载器,它除了能够加载类之外,还能够确认一个类在虚拟机中的惟一性(对于任意一个类,都必须由加载它的类加载器和这个类自己一块儿共同确立其在Java虚拟机中的惟一性),同一个类被同一个虚拟机加载,只要加载器不一样,那类一定也不一样。
java虚拟机经典的双亲委派模式。一幅图:
启动类加载器(BootstrapClassLoader):负责加载存放在 <JAVA_HOME>\lib目录,或者被-Xbootclasspath参数所指定的路径中存放的类到虚拟机中。
扩展类加载器(ExtClassLoader):负责加载<JAVA_HOME>\lib\ext目录中,或者被java.ext.dirs系统变量所 指定的路径中全部的类库。
应用程序类加载器(AppClassLoader):负责加载用户类路径 (ClassPath)上全部的类库。
基本机制:每当加载一个类的时候,虚拟机会先用启动类加载器进行加载,加载不到再用扩展类加载器,再加载不到就用应用程序类加载器进行加载。这样能够保证一个类在虚拟机里惟一。
本篇主要介绍了类文件结构以及类加载机制,整个类的加载过程仍是比较清晰且简单的,你们也能够本身试着定一个类加载器来加载类,跟进代码看一下双亲委派模式具体怎么走。