美文网首页程序员
JVM-类加载过程

JVM-类加载过程

作者: 我可能是个假开发 | 来源:发表于2023-02-11 10:13 被阅读0次

一、定义

类加载过程.png

从 class 文件到内存中的类,按先后顺序需要经过加载链接以及初始化三大步骤。

二、Java 语言的类型

1.基本类型(primitive types)

Java 的基本类型,是由 Java 虚拟机预先定义好的。

类型 值域 默认值 虚拟机内部符号
boolean {false,true} false Z
byte [-128,127] 0 B
short [-32768,32767] 0 S
char [0,65535] '\u0000' C
int [-231,231-1] 0 I
long [-263,263-1] 0L J
float ~[-3.4E38,3.4E38] +0.0F F
double ~[-1.8E308,1.8E308] +0.0D D

Java 的基本类型都有对应的值域和默认值。可以看到,byte、short、int、long、float 以及 double 的值域依次扩大,而且前面的值域被后面的值域所包含。因此,从前面的基本类型转换至后面的基本类型,无需强制转换。

他们的默认值看起来不一样,但在内存中都是 0。

2.引用类型(reference types)

  • 类:有对应的字节流
  • 接口:有对应的字节流
  • 数组类:由 Java 虚拟机直接生成
  • 泛型参数

无论是直接生成的数组类,还是加载的类,Java 虚拟机都需要对其进行链接和初始化。

由于泛型参数会在编译过程中被擦除,因此 Java 虚拟机实际上只有前三种。

三、加载

1.定义

查找字节流,并且据此创建类的过程

对于数组类来说,它并没有对应的字节流,而是由 Java 虚拟机直接生成的。
对于其他的类来说,Java 虚拟机则需要借助类加载器来完成查找字节流的过程。

2.类加载器

类加载器.png
  • 启动类加载器(bootstrap class loader):由 C++ 实现的,没有对应的 Java 对象,因此在 Java 中只能用 null 来指代。负责加载最为基础、最为重要的类,比如存放在 JRE 的 lib 目录下 jar 包中的类(以及由虚拟机参数 -Xbootclasspath 指定的类)
  • 扩展类加载器(extension class loader):Java 核心类库提供。负责加载相对次要、但又通用的类,比如存放在 JRE 的 lib/ext 目录下 jar 包中的类(以及由系统变量 java.ext.dirs 指定的类)
  • 应用类加载器(application class loader):Java 核心类库提供。负责加载应用程序路径下的类。(这里的应用程序路径,是指虚拟机参数 -cp/-classpath、系统变量 java.class.path 或环境变量 CLASSPATH 所指定的路径。)默认情况下,应用程序中包含的类便是由应用类加载器加载的。
  • 自定义类加载器:除了由 Java 核心类库提供的类加载器外,可以加入自定义的类加载器,来实现特殊的加载方式。比如可以对 class 文件进行加密,加载时再利用自定义的类加载器对其解密。

除了加载功能之外,类加载器还提供了命名空间的作用。

在 Java 虚拟机中,类的唯一性是由类加载器实例以及类的全名一同确定的。即便是同一串字节流,经由不同的类加载器加载,也会得到两个不同的类。在大型应用中,往往借助这一特性,来运行同一个类的不同版本。

启动类加载器之外,其他的类加载器都是 java.lang.ClassLoader 的子类,因此有对应的 Java 对象。

3.双亲委派模型

一个类加载器在加载类时,先把这个请求委托给自己的父类加载器去执行,如果父类加载器还存在父类加载器,就继续向上委托,直到顶层的启动类加载器。如果父类加载器能够完成类加载,就成功返回,如果父类加载器无法完成加载,那么子加载器才会尝试自己去加载。

好处:双亲委派模可以避免类的重复加载,另外也避免了 Java 的核心 API 被篡改。

打破双亲委派:重写loadClass方法

四、链接

链接,是指将创建成的类合并至 Java 虚拟机中,使之能够执行的过程。它可分为验证、准备以及解析三个阶段。

1.验证

确保被加载类能够满足 Java 虚拟机的约束条件。
Java 编译器生成的类文件必然满足 Java 虚拟机的约束条件。

2.准备

为被加载类的静态字段分配内存。
部分 Java 虚拟机还会在此阶段构造其他跟类层次相关的数据结构,比如说用来实现虚方法的动态绑定的方法表。

在 class 文件被加载至 Java 虚拟机之前,这个类无法知道其他类及其方法、字段所对应的具体地址,甚至不知道自己方法、字段的地址。因此,每当需要引用这些成员时,Java 编译器会生成一个符号引用。在运行阶段,这个符号引用一般都能够无歧义地定位到具体目标上。

举例来说,对于一个方法调用,编译器会生成一个包含目标方法所在类的名字、目标方法的名字、接收参数类型以及返回值类型的符号引用,来指代所要调用的方法。

3.解析

将第二阶段的符号引用解析成为实际引用。如果符号引用指向一个未被加载的类,或者未被加载类的字段或方法,那么解析将触发这个类的加载(但未必触发这个类的链接以及初始化。)

Java 虚拟机规范并没有要求在链接过程中完成解析。它仅规定了:如果某些字节码使用了符号引用,那么在执行这些字节码之前,需要完成对这些符号引用的解析。

五、初始化

如果要初始化一个静态字段,可以在声明时直接赋值,也可以在静态代码块中对其赋值。

如果直接赋值的静态字段被 final 所修饰,并且它的类型是基本类型或字符串时,那么该字段便会被 Java 编译器标记成常量值(ConstantValue),其初始化直接由 Java 虚拟机完成。除此之外的直接赋值操作,以及所有静态代码块中的代码,则会被 Java 编译器置于同一方法中,并把它命名为 < clinit >。

类加载的最后一步是初始化,便是为标记为常量值的字段赋值,以及执行 < clinit > 方法的过程。Java 虚拟机会通过加锁来确保类的 < clinit > 方法仅被执行一次。

只有当初始化完成之后,类才正式成为可执行的状态。

类的初始化触发时机

  • 1.当虚拟机启动时,初始化用户指定的主类;
  • 2.当遇到用以新建目标类实例的 new 指令时,初始化 new 指令的目标类;
  • 3.当遇到调用静态方法的指令时,初始化该静态方法所在的类;
  • 4.当遇到访问静态字段的指令时,初始化该静态字段所在的类;
  • 5.子类的初始化会触发父类的初始化;
  • 6.如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初始化,会触发该接口的初始化;
  • 7.使用反射 API 对某个类进行反射调用时,初始化这个类;
  • 8.当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的类。
public class Singleton {
  private Singleton() {}
  private static class LazyHolder {
    static final Singleton INSTANCE = new Singleton();
  }
  public static Singleton getInstance() {
    return LazyHolder.INSTANCE;
  }
}

只有当调用 Singleton.getInstance 时,程序才会访问 LazyHolder.INSTANCE,才会触发对 LazyHolder 的初始化(对应第 4 种情况),继而新建一个 Singleton 的实例。
由于类初始化是线程安全的,并且仅被执行一次,因此程序可以确保多线程环境下有且仅有一个 Singleton 实例。

极客时间《深入拆解 Java 虚拟机》 学习笔记 Day07 - http://gk.link/a/11WCN

相关文章

  • JVM-类加载过程

    一、定义 从 class 文件到内存中的类,按先后顺序需要经过加载、链接以及初始化三大步骤。 二、Java 语言的...

  • JVM类加载器与双亲委派模型(JDK8)

    引言 在上文JVM-类加载机制[https://imchenway.com/2021/07/01/JVM-%E7%...

  • JVM-类加载器

    JVM-类加载器 类与类加载器 对于类与类加载器有两种限定: 对于任意一个类,都需要由加载它的类加载器和这个类本身...

  • JAVA-大白话探索JVM-类加载过程(二)

    首先我们知道JVM是什么以及类加载器的作用 不清楚的可以看看JAVA-大白话探索JVM-类加载器(一) 现在我们来...

  • 第一章 类加载过程

    要点 类加载过程 类加载器 一、类加载过程 1.类的加载过程 类的加载 .class文件过程分为:加载---->连...

  • JVM-类加载机制

    1.类加载机制 1.1什么是类的加载 类的加载是将.class文件中的二进制数据读到内存中,并把它放到运行时数据区...

  • JVM-类加载机制

    一.类加载时机 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading)、验证...

  • JVM-类加载机制

    前言 近几个月学习了儒猿技术窝的专栏《从 0 开始带你成为JVM实战高手[https://apppukyptrl1...

  • JVM-类加载器

    类加载器 类加载器是用来把类加载到JAVA虚拟机中。 类加载的过程 类的加载过程采用了父亲委托的机制,这种机制能更...

  • JVM-对象内存布局

    jvm-对象内存布局 对象内存结构概述 对象的创建过程: jvm将对象所在的class文件加载到方法区中 jvm读...

网友评论

    本文标题:JVM-类加载过程

    本文链接:https://www.haomeiwen.com/subject/sqjkkdtx.html