JVM学习--编译过程和类加载机制

JVM学习–编译过程和类加载机制

本章学习java中类的编译过程和加载机制。部分内容参考Oracle官网以及咕泡学院教材。分析版本为jdk1.8。

/**
 * jvm学习测试使用对象
 * @author: to-be-continued
 * @Date: 2020/6/12 18:11
 */
@Data
public class Person implements Serializable {

    private Long id;


    private String name;


    public static void main(String[] args) {
        System.out.println(new Person());
    }

}

编译:javac Person.java 得到Person.class文件

运行:java Person.class

java中,虚拟机要运行这段代码,需要经过源码的编译过程->类加载->运行main方法。编译后生成class文件,然后通过java运行class文件。下面以Person对象为例介绍java编译过程。

编译过程

从上面可以看到,在经过javac Person.java之后,生成了一个Person.class文件,这中间是经过java编译器的编译过程得到的。过程如下:

Person.java -> 词法分析器 ->tokens流 -> 语法分析器 -> 语法树/抽象语法树 -> 语义分析器 -> 注解抽象语法树 -> 字节码生成器 -> Person.class

打开class文件是一大串看不懂的字节码,不是人能看懂的。如下所示:

CA FE BA BE 00 00 00 34  00 58 0A 00 1D 00 39 07
00 3A 0A 00 02 00 39 09  00 1C 00 3B 09 00 1C 00
3C 0B 00 3D 00 3E 0A 00  02 00 3F 0A 00 02 00 40
0A 00 02 00 3E 07 00 41  0A 00 42 00 43 07 00 44
0A 00 0A 00 45 0A 00 46  00 47 0B 00 3D 00 3F 06
40 00 00 00 00 00 00 00  06 40 08 00 00 00 00 00
00 06 40 10 00 00 00 00  00 00 06 40 14 00 00 00
00 00 00 06 40 18 00 00  00 00 00 00 06 40 1C 00
00 00 00 00 00 07 00 48  07 00 49 01 00 12 71 75
6F 74 65 53 74 61 74 75  73 57 65 69 67 68 74 73
01 00 0F 4C 6A 61 76 61  2F 75 74 69 6C 2F 4D 61
70 3B 01 00 09 53 69 67  6E 61 74 75 72 65 01 00
36 4C 6A 61 76 61 2F 75  74 69 6C 2F 4D 61 70 3C
4C 6A 61 76 61 2F 6C 61  6E 67 2F 49 6E 74 65 67
65 72 3B 4C 6A 61 76 61  2F 6C 61 6E 67 2F 44 

这个时候可以参考一下官网的介绍。自此得到class文件后,可以开始运行class文件了。

The class File Format

类加载机制

类的加载过程经过Loading(加载)、Linking(链接)和Initializing(初始化),在Oracle官网中提供了对于加载、链接、初始化的定义。参见:

Loading、Linking、Initializing

The Java Virtual Machine dynamically loads, links and initializes classes and interfaces. Loading is the process of finding the binary representation of a class or interface type with a particular name and creating a class or interface from that binary representation. Linking is the process of taking a class or interface and combining it into the run-time state of the Java Virtual Machine so that it can be executed. Initialization of a class or interface consists of executing the class or interface initialization method <clinit> (§2.9).

In this chapter, §5.1 describes how the Java Virtual Machine derives symbolic references from the binary representation of a class or interface. §5.2 explains how the processes of loading, linking, and initialization are first initiated by the Java Virtual Machine. §5.3 specifies how binary representations of classes and interfaces are loaded by class loaders and how classes and interfaces are created. Linking is described in §5.4. §5.5 details how classes and interfaces are initialized. §5.6 introduces the notion of binding native methods. Finally, §5.7 describes when a Java Virtual Machine exits.

直译:Java虚拟机动态加载、链接和初始化类和接口。加载是查找具有特定名称的类或接口类型的二进制表示,并从该二进制表示创建类或接口的过程。链接是获取类或接口并将其结合到Java虚拟机的运行时状态以便执行的过程。类或接口的初始化由执行类或接口的初始化方法组成。(§2.9)。

在这一章中,§5.1描述了Java虚拟机如何从类或接口的二进制表示中获取符号引用。§5.2解释了Java虚拟机是如何首先启动加载、链接和初始化过程的。§5.3指定类装入器如何装入类和接口的二进制表示,以及类和接口如何创建。链接在§5.4中进行了描述。5.5详细说明了类和接口是如何初始化的。5.6介绍了绑定本机方法的概念。最后,§5.7描述了Java虚拟机何时退出

加载(Loading)

查找和导入class文件

(1)通过类的全限定名获取定义此类的二进制字节流

(2)将字节流所代表的静态结构转化为方法区的运行时数据结构

(3)在java堆中生成此类的class对象,作为对方法区中这些数据的访问入口

链接(Linking)

Linking a class or interface involves verifying and preparing that class or interface, its direct superclass, its direct superinterfaces, and its element type (if it is an array type), if necessary. Resolution of symbolic references in the class or interface is an optional part of linking.

This specification allows an implementation flexibility as to when linking activities (and, because of recursion, loading) take place, provided that all of the following properties are maintained:

  • A class or interface is completely loaded before it is linked.
  • A class or interface is completely verified and prepared before it is initialized.
  • Errors detected during linkage are thrown at a point in the program where some action is taken by the program that might, directly or indirectly, require linkage to the class or interface involved in the error.

For example, a Java Virtual Machine implementation may choose to resolve each symbolic reference in a class or interface individually when it is used (“lazy” or “late” resolution), or to resolve them all at once when the class is being verified (“eager” or “static” resolution). This means that the resolution process may continue, in some implementations, after a class or interface has been initialized. Whichever strategy is followed, any error detected during resolution must be thrown at a point in the program that (directly or indirectly) uses a symbolic reference to the class or interface.

从官网介绍得出,链接一个类或者接口需要经过验证、准备、解析过程。

验证(Verification)

保证类加载的正确性

  • 文件格式验证
  • 元数据验证
  • 字节码验证
  • 符号引用验证
准备(Preparation)

为类的静态变量分配内存,将其初始化为默认值

解析(Resolution)

把类中的符号引用转换为直接引用

初始化(Initializing)

对类中存在的静态变量、静态代码块执行初始化操作

加载过程图解

在这里插入图片描述

类加载器

ClassLoader为加载阶段用来装载class文件的。

分类

1)Bootstrap ClassLoader 负责加载 J A V A H O M E 中 j r e / l i b / r t . j a r 里 所 有 的 c l a s s 或 X b o o t c l a s s o a t h 选 项 指 定 的 j a r 包 。 由 C + + 实 现 , 不 是 C l a s s L o a d e r 子 类 。 2 ) E x t e n s i o n C l a s s L o a d e r 负 责 加 载 j a v a 平 台 中 扩 展 功 能 的 一 些 j a r 包 , 包 括 JAVA_HOME中 jre/lib/rt.jar 里所有的class或 Xbootclassoath选项指定的jar包。由C++实现,不是ClassLoader子类。 2)Extension ClassLoader 负责加载java平台中扩展功能的一些jar包,包括 JAVAHOMEjre/lib/rt.jarclassXbootclassoathjarC++ClassLoader2ExtensionClassLoaderjavajarJAVA_HOME中
jre/lib/*.jar 或 -Djava.ext.dirs指定目录下的jar包。
3)App ClassLoader 负责加载classpath中指定的jar包及 Djava.class.path 所指定目录下的类和
jar包。
4)Custom ClassLoader 通过java.lang.ClassLoader的子类自定义加载class,属于应用程序根据
自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现ClassLoader。

加载原则

检查某个类是否已经加载:顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检
查,只要某个Classloader已加载,就视为已加载此类,保证此类只所有ClassLoader加载一次。
加载的顺序:加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。

扩展:这里用到了双亲委派机制来实现。

双亲委派机制
定义:如果一个类加载器在接到加载类的请求时,它首先不会自己尝试去加载这个类,而是把
这个请求任务委托给父类加载器去完成,依次递归,如果父类加载器可以完成类加载任务,就
成功返回;只有父类加载器无法完成此加载任务时,才自己去加载。
优势:Java类随着加载它的类加载器一起具备了一种带有优先级的层次关系。比如,Java中的
Object类,它存放在rt.jar之中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型
最顶端的启动类加载器进行加载,因此Object在各种类加载环境中都是同一个类。如果不采用
双亲委派模型,那么由各个类加载器自己取加载的话,那么系统中会存在多种不同的Object
类。
破坏:可以继承ClassLoader类,然后重写其中的loadClass方法,其他方式大家可以自己了解
拓展一下。

引用自咕泡学院教材

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值