也许我们对JVM很陌生,但是我们对基于配置的框架应该比较熟悉。我们暂且认为我们是在加载一个简单的xml,并且并不关心具体细节
XML加载
- 定位/加载 Java原生的URL定位/Spring中的上级抽象Resource
- 验证 基于DTD格式的验证/基于XSD格式的验证
- 解析 DOM解析/SAX解析
- 初始化 根据XML中的定义执行自定义逻辑
JVM加载类的字节码其实跟程序加载XML极其类似,却远比XML复杂。
JVM类加载
加载
JVM加载阶段虚拟机规范定义了需要完成三件事情
- 通过一个类的全限定名来获取此类的二进制字节流
- 将这个字节流所代表的静态字段存储结构转化为方法区运行时数据结构。
- 在内存中生存一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
这三条并不算具体,因此虚拟机实现与具体应用的灵活度的实现都相当的大。
可能的加载来源
- 从ZIP包中读取 JAR/EAR/WAR
- 从网络中获取 Applet
- 运行时动态生成 动态代理技术
- 由其它文件生成 JSP/JSF
- 从数据库中读取 相对少见 SAP Netweaver
加载来源的抽象
java将不同来源的资源抽象成URL,通过注册不同的handler(URLStreamHandler)来处理不同来源的资源的读取逻辑。然而一般的框架(或者说程序)都会定义来源的上层抽象,Spring的加载XML时定义的是Resource,JVM的定义的则是Repository。
验证
验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。这是一个非常重要的但不是必要的阶段。可以考虑在实施阶段使用-Xverify:none参数来关闭大部分的类的验证以缩短虚拟机类加载的时间
验证的四个步骤
- 文件格式验证
- 元数据校验
- 字节码验证
- 符号引用校验
更多请移步java虚拟机规范
准备
准备阶段是正式为类变量分配内存并设置初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。
public static int value1 = 123; //分配后为0
public final static int vaule2 = 123; //分配后为123
解析
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程
虚拟机规范并未规定解析阶段发生的具体时间,只要求在执行了anewarray/checkcast/getfield等一共16个用于操作符号引用的字节码指令之前,需要先对它们所使用的符号引用进行解析,所以虚拟机的具体实现可能不同。
解析类别
- 类或接口的解析
- 字段解析
- 类方法解析
- 接口方法解析
- 方法类型和方法处理解析
- 调用点描述符解析
更多请移步java虚拟机规范
初始化
类的初始化是类加载过程的最后一部,到了初始化阶段就真正开始执行类中定义的java字节码了。
参考
《深入理解JAVA虚拟机》第二版
由于现在jdk已经到了11,书算是比较老。具体细节和更多信息可以直接阅读虚拟机规范
网友评论