第一章 JVM 概述
第二章 JVM 编译
第三章 JVM 类结构
第四章 JVM 类加载机制

本文不是 Loading, Linking, and Initializing 的翻译,仅仅是对虚拟机类加载机制的一些个人看法以及我认为重点的整理,欢迎阅读和指正。

1. JVM 类加载机制概览

JVM 类加载机制就是把编译好的 class 文件装载进虚拟机内存,并创建和初始化成可以被 JVM 执行的对象,然后存入方法区的过程。
在这里插入图片描述

2. JVM 首次加载、链接和初始化

JVM 规范规定虚拟机启动通过创建初始类开始,初始类用 bootstrap 类加载器加载,不同的 JVM 实现机制会有一些不同。初始类可以由命令行参数指定,也可以使用自定义的类加载器,从自定义的路径加载。
在这里插入图片描述

3. JVM 类加载过程

主要分成三大步骤:

3.1 加载

加载的过程是找到二进制表示的类文件,然后根据这个文件创建类或接口。

3.1.1 运行时常量池的创建

JVM 在创建类和接口的时候,用类文件中的常量池构建成了运行时常量池。最初的时候运行时常量池中的引用是符号引用。下图表示了常量池和运行时常量池的派生关系。
在这里插入图片描述

3.1.2 类加载器

下图是 Lanucher 和 ClassLoader类的一些实现机制。
在这里插入图片描述

3.2 链接

链接的过程是取一个类或者接口,并将其组合成 JVM 的运行时状态,以使它可以被 JVM 执行。
在这里插入图片描述

1.2.1 验证

验证字节码结构是否正确。

1.2.2 准备

类属性的创建、赋默认值然后做一些校验。

1.2.3 解析

解析是从运行池常量池的符号引用中动态确定具体值的过程,符号引用可以重复解析并且解析后的值是相同的。在执行这些指令anewarray, checkcast, getfield, getstatic, instanceof, invokedynamic, invokeinterface, invokespecial, invokestatic, invokevirtual, ldc, ldc_w, multianewarray, new, putfield, and putstatic之前,符号引用需要先解析成直接引用。

1.2.3.1 类或接口解析
1.2.3.1.1 使用类加载器加载创建对应的类
1.2.3.1.2 如果是数组并且元素类型是引用类型,递归调用类或接口解析来解析,具体步骤可以参考 1.2.3.1
1.2.3.1.3 校验是否有访问权限
1.2.3.2 字段解析

先确保字段的类或接口已被解析;然后查找当前的类,如果当前类可以找到这个字段就返回成功;如果当前类不能找到,递归查找它的父类;如果查询完所有的父类都查询不到,就认为解析失败NoSuchFieldError;如果可以解析,但是没有访问权限,报IllegalAccessError

1.2.4 访问控制

根据关键字 PUBLIC、PROTECTED、DEFAULT、PRIVATE 确定类或者接口、字段和方法是否有访问权限。

1.2.5 重载

3.3 初始化

初始化的过程是取一个类或者接口并执行它们的初始化方法 <clinit>

3.3.1 初始化的时机

当执行指令new, getstatic, putstatic, or invokestatic,调用反射方法,子类初始化,类被标记为虚拟机启动的 initial 类时会触发类或接口的初始化。初始化之前类或接口必须完成链接,但是不需要完成解析。由于可能有多个线程同时初始化相同的类,因此初始化时需要做并发控制。

3.4 本地方法绑定

本地方法在运行时也需要加载到 JVM 中以便 JVM 可以调用执行。

3.5 虚拟机退出

执行以下代码时触发虚拟机退出:

Runtime.exit()
System.exit()
Runtime.halt()
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐