加载是根据特定名称查找类或接口类型的二进制表示(Binary Representation),并由此二进制表示创建类或接口的过程。

加载,就是指去寻找类或接口的过程。

链接是为了让类或接口可以被 Java 虚拟机执行,而将类或接口并入虚拟机运行时状态的过程。

链接,就是将类或接口与JVM链接起来的过程。

类或接口的初始化是指执行类或接口的初始化方法(§ 2.9)

初始化,就是执行方法的过程。

Java 虚拟机为每个类型都维护一个常量池。

这里注意关键词「每个类型」,也就是说整型是一个常量池,字符串类型也是一个常量池。

运行时常量池中的所有引用最初都是符号引用。

符号引用的意思是它只是一个符号,需要后续通过链接,替换为具体的内存地址。

这里说的符号引用,下面列举几种:

  • CONSTANT_Fieldref_info 类或接口的某个字段的符号引用
  • CONSTANT_Methodref_info 类中某个方法的符号引用
  • CONSTANT_InterfaceMethodref_info 接口的某个方法的符号引用
  • CONSTANT_MethodHandle_info 方法句柄的符号引用
  • 等等

创建和加载

Java 虚拟机的启动是通过引导类加载器(Bootstrap Class Loader § 5.3.1) 创建一个初始类(Initial Class)来完成,这个类是由虚拟机的具体实现指定。紧接着, Java 虚拟机链接这个初始类,初始化并调用它的 public void main(String[])方法。之后的整个执行过程都是由对此方法的调用开始。执行 main 方法中的 Java 虚拟机指令可能会导致 Java 虚拟机链接另外的一些类或接口,也可能会调用另外的方法。

简单地说,虚拟机通过链接初始类,由此会调用其他类或接口,从而开始整个庞大Java项目的运行。

首先,Java 虚拟机检查引导类加载器是否是已加载过的标记为 N 的类或接口的初始加载器。如果是的话,这个类或接口就是 C,并且不再创建其它类型。否则, Java 虚拟机将参数 N 传递给引导类加载器的特定方法,以平台相关的方式搜索 C 的描述。典型的情况是,类或文件会被表示为树型文件系统中的某个文件,类或接口的名称就是此文件的路径名。

这段话描述了引导类加载器如何加载类或接口,可以详细看看。

首先, Java 虚拟机检查 L 是否为已经加载过的标识为 N 的类或接口的初始加载器。如果是的话,那个类或接口就是 C,不用再创建其它类了。否则 Java 虚拟机会调用 L 的 loadClass(N)①方法。 这次调用的返回值就是创建好的类或接口 C。 Java 虚拟机会记录下 L 是 C 的初始加载器(§ 5.3.4)。这节其余的部分会更详细地描述这个过程。

这段话描述了自定义类加载器如何加载类或接口。

链接

类加载器需要特别考虑到类型的安全链接问题。一种可能出现的情况是,当两个不同的类加载器初始加载标记为 N 的类或接口时,在每个加载器里 N 表示着不同的类或接口。

这里的意思或许是说,一个同样的类被加载在不同的类加载器中,其表示两个完全不同的类。即使这些类或接口的字节码完全相同。

《Java 虚拟机规范》 允许灵活地选择链接(并且会有递归加载)发生的时机。

链接过程可以灵活选择。

例如,Java 虚拟机实现可以选择只有在使用类或接口中符号引用时才去逐一解析它(延迟解析),或是当类在验证时就解析每个引用(预先解析)。这意味着在一些虚拟机实现中,在类或接口被初始化动作开始后,解析动作可能还正在进行。

解析过程可以延迟解析,也可以预先解析。

验证(Verification, § 4.10)阶段用于确保类或接口的二进制表示结构上是正确的。验证过程可能会导致某些额外的类和接口被加载进来(§ 5.3),但不应该会导致它们也需要验证或准备。

验证会导致其他类的加载但不会导致它们也需要验证或准备。

准备(Preparation)阶段的任务是为类或接口的静态字段分配空间,并用默认值初始化这些字段(§ 2.3, § 2.4)。这个阶段不会执行任何的虚拟机字节码指令。

准备阶段是为类或接口的静态字段分配空间,并用默认值初始化这些字段。注意,并不会执行任何虚拟机字节码指令。

Java 虚拟机指令 anewarray、 checkcast、 getfield、 getstatic、 instanceof、nvokedynamic、 invokeinterface、 invokespecial、 invokestatic、 invokevirtual、ldc、 ldc_w、 multianewarray、 new、 putfield 和 putstatic将符号引用指向运行时常量池。执行上述任何一条指令都需要对它的符号引用的进行解析。

解析就是解析符号引用的过程,将其转为具体的值。

解析(Resolution)是根据运行时常量池的符号引用来动态决定具体的值的过程。

接下来的大部分内容,都是对于特定内容的解析步骤,例如:对于类或接口解析、字段解析、普通方法解析、接口方法解析、调用点限定符解析等。这部分内容确实晦涩难懂,建议大致通读一遍就好,暂时不要深究。

初始化

初始化(Initialization) 对于类或接口来说,就是执行它的初始化方法(§ 2.9)。

这里就是开始执行初始化方法了,包括和两个初始化方法。具体有5种情况下会触发这种初始化。

1、在执行下列需要引用类或接口的 Java 虚拟机指令时: new, getstatic, putstatic或 invokestatic。这些指令通过字段或方法引用来直接或间接地引用其它类。执行上面所述的 new 指令,在类或接口没有被初始化过时就初始化它。执行上面的 getstatic,
putstatic 或 invokestatic 指令时,那些解析好的字段或方法中的类或接口如果还没有被初始化那就初始化它。
2、在初次调用 java.lang.invoke.MethodHandle 实例时,它的执行结果为通过 Java虚拟机解析出类型是 2(REF_getStatic)、 4(REF_putStatic)或者 6(REF_invokeStatic)的方法句柄(§ 5.4.3.5)。
3、在调用 JDK 核心类库中的反射方法时,例如, Class 类或 java.lang.reflect 包。
4、在对于类的某个子类的初始化时。
5、在它被选定为 Java 虚拟机启动时的初始类(§ 5.2) 时。

JVM规范系列文章目录

JVM规范系列第5章:加载、链接与初始化的更多相关文章

  1. JVM详解之:类的加载链接和初始化

    目录 简介 加载 运行时常量池 类加载器 链接 验证 准备 解析 初始化 总结 简介 有了java class文件之后,为了让class文件转换成为JVM可以真正运行的结构,需要经历加载,链接和初始化 ...

  2. JVM规范系列第1章:引言

    如果你还没下载<Java虚拟机规范>这本书,那么先点击这里下载再一块儿看吧. 前言 Java 虚拟机是一个抽象化的机器,整个规范中提及的 Java 虚拟机都是抽象化的概念,而不是特指 Or ...

  3. JVM规范系列第2章:Java虚拟机结构

    本规范描述的是一种抽象化的虚拟机的行为,而不是任何一种(译者注:包括 Oracle 公司自己的 HotSpot 和 JRockit 虚拟机)被广泛使用的虚拟机实现. 记住:JVM规范是一种高度抽象行为 ...

  4. JVM规范系列第3章:为Java虚拟机编译

    Oracle 的 JDK 包括两部分内容:一部分是将 Java 源代码编译成 Java 虚拟机的指令集的编译器,另一部分是用于Java 虚拟机的运行时环境. 第一部分应该说的是 Javac 这个前置编 ...

  5. JVM规范系列第4章:Class文件格式

    这一章节讲的是字节码的整个组成格式,读懂了这一章,就读懂了字节码文件.对于这一章的学习,我更推荐作为工具书去查找.最好是找一个最简单的Hello World例子,一个字节一个字节去分析其含义.在分析过 ...

  6. JVM规范系列第6章:Java虚拟机指令集

    一条 Java 虚拟机指令由一个特定操作的操作码和零至多个操作所使用到的操作数所构成. 虚拟机指令 = 操作码 + 操作数. 其中,操作码值分别为 254(0xfe)和 255(0xff),助记符分别 ...

  7. JVM规范系列开篇:为什么要读JVM规范?

    许多人知道类加载机制.JVM内存模型,但他们可能不知道什么是<Java虚拟机规范>.对于Java开发来说,<Java虚拟机规范>才是最为官方.准确的一个文档,了解这个规范可以让 ...

  8. JVM规范系列:总结

    我们花了几天的时间来阅读<Java虚拟机规范>,了解要实现一个虚拟机应该包括什么内容.通过这么一次阅读,我们大致了解了虚拟机规范的内容. 第1章.对Java虚拟机进行了一些简单的介绍. 第 ...

  9. 《Entity Framework 6 Recipes》中文翻译系列 (22) -----第五章 加载实体和导航属性之延迟加载

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第五章 加载实体和导航属性 实体框架提供了非常棒的建模环境,它允许开发人员可视化地使 ...

随机推荐

  1. Java同步、异步区别

    一.概念: 1.同步:所有的操作都做完,才返回给用户.这样用户在线等待的时间太长,给用户一种卡死了的感觉(就是系统迁移中,点击了迁移,界面就不动了,但是程序还在执行,卡死了的感觉).这种情况下,用户不 ...

  2. python写一个双色球彩票计算器

    首先声明,赌博一定不是什么好事,也完全没有意义,不要指望用彩票发财.之所以写这个,其实是用来练手的,可以参考这个来预测一些其他的东西,意在抛砖引玉. 啰嗦完了,马上开始,先上伪代码 打开网址 读取内容 ...

  3. tkinter内嵌Matplotlib系列(一)之解读官网教材

    目录 目录 前言 (一)小目标 1.首页卷面: 2.绘制一条函数曲线: 3.绘制多条曲线: (二)官方教材 1.对GUI框架的支持: 2.内嵌于tkinter的说明文档: (三)对官方教程的解读 目录 ...

  4. 真机测试以及appstore发布流程

    一.添加真机测试流程:http://jingyan.baidu.com/article/48b558e33b96a27f38c09aa4.html 二.app发布流程:http://jingyan.b ...

  5. markdownpad破解

    下载在腾讯软件下载比较快. 破解我就不写步骤了,直接给个链接 https://blog.csdn.net/geekqian/article/details/74455409 授权邮箱:Soar360@ ...

  6. java用星星符号打印出一个直角三角形

    package debug; public class Demo10 { public static void main(String[] args) { //用星星符号打印出一个直角三角形 for( ...

  7. node_01_自定义模块(先创建package.json)

    package.json必须是json格式 你必须确保所有的字符串,包括属性名,都是使用双引号而不是单引号 { "name": "163", "ver ...

  8. 通过css3,实现加载转动贝塞尔曲线动画

    参考博客:http://blog.jobbole.com/94966/ css代码: .loading { position : relative; display : inline-block; w ...

  9. 初探boost之timer库学习笔记

    timer   使用方法     #include <boost/timer.hpp> #include <iostream> using namespace std; usi ...

  10. NET Framework 各版本官方下载

    https://msdn.microsoft.com/en-us/library/5a4x27ek(v=vs.110).aspx https://www.microsoft.com/zh-CN/dow ...