Java JVM类加载机制原理剖析

目录

    • 前言
    • 一、什么是类加载
    • 二、类加载子系统
    • 三、类的加载过程
      • 2.1、加载
      • 2.2、验证
      • 2.3、准备
      • 2.4、解析
      • 2.5、初始化
    • 四、类加载器(ClassLoader)

前言

      Java类要加载到JVM中的,会经过一系列的加载过程,这个过程就是在类加载子系统中实现的,当我们用Java命令运行某个类的main函数启动程序时,首先需要通过类加载器把主类加载到JVM中,本文会对这个加载过程以及双亲委派机制做剖析。
在这里插入图片描述

一、什么是类加载

      类加载其实是在硬盘上查找通过io读入字节码文件(class文件)并加载到JVM方法区/元空间中作为一个元数据模板,可以根据这个模板实例化出N个一模一样的实例对象,一个类只会被加载一次,并且是第一次使用时动态加载的。

  • 加载.calss文件的方式:
    • 从本地系统直接加载
    • 通过网络下载.class
    • 从zip、jar、war等归档文件中加载.class

二、类加载子系统

在这里插入图片描述

  • 类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识。

  • 加载阶段只负责class文件的加载,至于它是否可以运行,则由字节码执行引擎决定。

  • 加载的类信息存放于一块称为方法区/元空间的内存空间。除了类的信息外,方法区/元空间中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射),不同版本JDK也有各自的区别。

三、类的加载过程

      当JVM需要用到某个类时,虚拟机会加载它的.class文件,加载了相关的字节码信息后,会为它创建对应的Class对象,而这个过程就被称为类加载。但需额外注意的是:类加载机制只负责class文件的加载,至于是否可以执行,则是由执行引擎决定。
      类的生命周期包括 加载 >> 验证 >> 准备 >> 解析 >> 初始化 >> 使用 >> 卸载这7个阶段,其中类加载过程为加载 >> 验证 >> 准备 >> 解析 >> 初始化
在这里插入图片描述

2.1、加载

加载阶段是由类加载器进行的,加载.class文件的方式有:

从本地系统中直接加载
通过网络获取
从zip压缩包中读取,比如:jar、war格式的文件
运行时计算生成,如:动态代理技术

  • 加载过程完成以下三件事:
    • 1、通过类的完全限定名称获取定义该类的二进制字节流。
    • 2、将该字节流表示的静态存储结构转换为方法区的运行时存储结构。
    • 3、在内存中生成一个代表该类的 Class 对象,作为方法区/元空间中该类各种数据的访问入口。

2.2、验证

JVM 会在该阶段对二进制字节流进行校验,只有符合 JVM 字节码规范的才能被 JVM 正确执行。该阶段是保证 JVM 安全的重要屏障,下面是一些主要的检查。

  • 确保二进制字节流格式符合预期(比如说是否以 cafe bene 开头)。
  • 是否所有方法都遵守访问控制关键字的限定。
  • 方法调用的参数个数和类型是否正确。
  • 确保变量在使用之前被正确初始化了。
  • 检查变量是否被赋予恰当类型的值。

2.3、准备

  • JVM 会在该阶段对类变量(也称为静态变量,static 关键字修饰的)分配内存并初始化(对应数据类型的默认初始值,如 0、0L、null、false 等),此时不会分配实例变量的内存,因为实例变量是在实例化对象时一起创建在Java 堆中的。从概念上讲,类变量所使用的内存都应当在 方法区/元空间 中进行分配。不过有一点需要注意的是:JDK 7 之前,HotSpot 使用永久代来实现方法区的时候,实现是完全符合这种逻辑概念的。 而在 JDK 7 及之后,HotSpot 已经把原本放在永久代的字符串常量池、静态变量等移动到堆中,这个时候类变量则会随着 class 对象一起存放在 Java 堆中。
  • 这里所设置的初始值"通常情况"下是数据类型默认的零值(如 0、0L、null、false 等),比如我们定义了public static int i=996 ,那么 i 变量在准备阶段的初始值就是 0 而不是 996(初始化阶段才会赋值)。特殊情况:比如给 value 变量加上了 final 关键字public final static int i=996 ,那么准备阶段 i 的值就被赋值为 996。

2.4、解析

  • 该阶段将常量池中的符号引用转化为直接引用。
  • 在 class 文件中常量池里面存放了字面量和符号引用,符号引用包括类和接口的全限定名以及字段和方法的名称与描述符。
  • 在 JVM 动态链接的时候需要根据这些符号引用来转换为直接引用存放内存使用。

2.5、初始化

  • 初始化阶段就是执行类构造器方法()的过程;
  • 此方法不需要定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来;
  • 构造器方法中指令按语句在源文件中出现的顺序执行;
  • 初始化,为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。在Java中对类变量进行初始值设定有两种方式:
    • 声明类变量是指定初始值
    • 使用静态代码块为类变量指定初始值
public class ClassInitDemo {
    private static int a = 1;

    // 静态代码块 在类初始化时调用
    static {
        System.out.println(a); //1
        a = 10;
        b = 20;
        System.out.println(a); //10
        //System.out.println(number);    //报错:非法的前向引用(可以赋值,但不能调用)
    }

    //链接阶段的准备环节:b = 0 --> 初始化阶段:2 --> 20
    private static int b = 2;

    // 代码块 会在实例前调用
    {
        System.out.println("代码块");
    }

    public ClassInitDemo(){
        System.out.println("ClassInitDemo");
    }

    public static void main(String[] args) {
        System.out.println(ClassInitDemo.a); // 10
        System.out.println(ClassInitDemo.b); // 20
        ClassInitDemo classInitDemo = new ClassInitDemo();
    }
}

类初始化时机

只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下六种:

  • 创建类的实例,也就是new的方式
  • 访问某个类或接口的静态变量,或者对该静态变量赋值
  • 调用类的静态方法
  • 使用 java.lang.reflect 包的方法对类进行反射调用时,(如Class.forName(“com.kerwin.Test”)、newInstance())
  • 初始化一个类,如果其父类还未初始化,则先触发该父类的初始化
  • 当虚拟机启动时,用户需要定义一个要执行的主类 (包含 main 方法的那个类),虚拟机会先初始化这个类。
  • 当一个接口中定义了 JDK8 新加入的默认方法(被 default 关键字修饰的接口方法)时,如果有这个接口的实现类发生了初始化,那该接口要在其之前被初始化。

四、类加载器(ClassLoader)

在这里插入图片描述

  • 引导/启动类加载器: Bootstrap ClassLoader,负责加载存放在jdk\jre\lib(jdk代表jdk的安装目录,下同)下,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库(如rt.jar,所有的java.*开头的类,比如java.lang.Integer均被Bootstrap ClassLoader加载)。启动类加载器是无法被Java程序直接引用的。

    注意:因为JVM是通过全限定名加载类库的,所以,如果你的文件名不被虚拟机识别,就算你把jar包丢入到lib目录下,引导类加载器也并不会加载它。出于安全考虑,Bootstrap启动类加载器只加载包名为java、javax、sun等开头的类文件。

  • 扩展类加载器: Extension ClassLoader,该加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载JDK\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库(如javax.*开头的类),开发者可以直接使用扩展类加载器。

    这个类加载器是由sun公司实现的,位于HotSpot源码目录中的sun.misc.Launcher$ExtClassLoader位置。它主要负责加载<JAVA_HOME>\lib\ext目录下或者由系统变量-Djava.ext.dir指定位路径中的类库。它可以直接被开发者使用。

  • 系统/应用程序类加载器: Application ClassLoader,也被称为应用程序类加载器,也是由sun公司实现的,位于HotSpot源码目录中的sun.misc.Launcher$AppClassLoader位置。它负责加载系统类路径java -classpath或-D java.class.path指定路径下的类库,也就是经常用到的classpath路径。应用程序类加载器也可以直接被开发者使用。

    一般情况下,该类加载器是程序的默认类加载器,我们可以通过ClassLoader.getSystemClassLoader()方法可以直接获取到它。

  • 自定义类加载器: Application ClassLoader,也被称为应用程序类加载器,也是由sun公司实现的,位于HotSpot源码目录中的sun.misc.Launcher$AppClassLoader位置。它负责加载系统类路径java -classpath或-D java.class.path指定路径下的类库,也就是经常用到的classpath路径。应用程序类加载器也可以直接被开发者使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/234792.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

函数栈帧的创建和销毁

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 1. 什么是函数栈帧 2. 理解函数栈帧能解决什么问题呢&#xff1f; 3. 函数栈帧的创建和销毁解析 3.1 什么是栈&#xff1f; 3.2 认识相关寄存器和汇编指令 3.3…

【深度学习】注意力机制(一)

本文介绍一些注意力机制的实现&#xff0c;包括SE/ECA/GE/A2-Net/GC/CBAM。 目录 一、SE&#xff08;Squeeze-and-Excitation&#xff09; 二、ECA&#xff08;Efficient Channel Attention&#xff09; 三、GE&#xff08;Gather-Excite&#xff09; 四、A2-Net(Double A…

USB基础知识点介绍

本文主要介绍USB2.0相关的知识点。 USB 2.0介绍 USB 2.0是一种通用串行总线&#xff08;Universal Serial Bus&#xff09;的接口标准&#xff0c;是USB&#xff08;Universal Serial Bus&#xff09;技术的第二代版本。它于2000年4月发布&#xff0c;是USB 1.1的升级版本。 …

交易历史记录20231208 记录

昨日回顾&#xff1a; SELECT TOP 10000 CODE,成交额排名,净流入排名,代码,名称,DDE大单金额,涨幅,所属行业,主力净额,DDE大单净量,CONVERT(DATETIME, 最后涨停时间, 120) AS 最后涨停时间 FROM dbo.全部&#xff21;股20231208_ALL WHERE 连板天 > 1AND DDE大单净量 > …

通信:mqtt学习网址

看这个网址&#xff1a;讲的很详细&#xff0c;后面补实战例子 第一章 - MQTT介绍 MQTT协议中文版 (gitbooks.io)https://mcxiaoke.gitbooks.io/mqtt-cn/content/mqtt/01-Introduction.html

3.DevEco Studio安装鸿蒙手机app本地模拟器

配合Intel CPU启动模拟器 解决措施 打开任务管理器&#xff0c;在“性能”选项&#xff0c;检查CPU虚拟化是否已经启用。如果未启用&#xff0c;需要进入电脑的BIOS中&#xff0c;将CPU的“Intel Virtualization Technology”选项开启。 点击New Emulator 文档中心 解决措施…

python+pytest接口自动化(12)-自动化用例编写思路 (使用pytest编写一个测试脚本)

经过之前的学习铺垫&#xff0c;我们尝试着利用pytest框架编写一条接口自动化测试用例&#xff0c;来厘清接口自动化用例编写的思路。 我们在百度搜索天气查询&#xff0c;会出现如下图所示结果&#xff1a; 接下来&#xff0c;我们以该天气查询接口为例&#xff0c;编写接口测…

Android Studio连接MYSQL数据库

首先导入mysql的jar包&#xff0c;这里连接的是8版本的。 这里之前到如果mysql的jar包了 首先跳到Project模式&#xff1a; 直接复制粘贴到这里&#xff1a; 这里之前到如果了。想删掉重新导入一次&#xff0c;但是报错,什么ioexception。这里将Project Structure中的Moudle中的…

【每日一题】—— D. Divide and Equalize(Codeforces Round 903 (Div. 3))(数学、数论)

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;每日一题 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日反刍 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓称…

【分治】最接近点对Python实现

文章目录 [toc]问题描述一维最接近点对算法Python实现 二维最接近点对算法分治算法时间复杂性Python实现 问题描述 给定平面上 n n n个点&#xff0c;找其中的一对点&#xff0c;使得在 n n n个点组成的所有点对中&#xff0c;该点对的距离最小 一维最接近点对算法 Python实…

探索无监督域自适应,释放语言模型的力量:基于检索增强的情境学习实现知识迁移...

深度学习自然语言处理 原创作者: Xnhyacinth 在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;如何有效地进行无监督域自适应(Unsupervised Domain Adaptation, UDA) 一直是研究的热点和挑战。无监督域自适应的目标是在目标域无标签的情况下&#xff0c;将源域的知识…

docker安装elasticsearch和kibana

docker系列 1、CentOS7安装docker 2、docker安装rabbitmq 3、docker安装mysql docker安装elasticsearch和kibana docker系列一、安装elasticsearch二、安装kibana三、安装ik分词器1、分词器说明2、安装分词器 本篇文章所采用的elasticsearch和kibana版本以及ik分词器都是7.12.…

AS安装目录

编辑器&#xff1a; sdk: gradle: gradle使用的jdk目录&#xff1a;Gradle使用的jdk是android studio安装目录下的jbr 成功项目的android studio配置&#xff1a;

动态内存的管理malloc、free、calloc、realloc

身在井隅&#xff0c;心向星光 眼里有诗&#xff0c;自在远方 目录 动态内存的简单介绍 动态内存的优势 可以控制内存的大小 可以多次利用这部分空间 动态内存函数malloc、free malloc开辟函数 free释放函数 动态内存函数calloc、realloc calloc开辟函数 realloc调整函数 动…

生产问题: 利用线程Thread预加载数据缓存,其它类全局变量获取缓存偶发加载不到

生产问题: 利用线程Thread预加载数据缓存偶发加载不到 先上代码 public class ThreadTest {//本地缓存Map<String, Object> map new HashMap<String, Object>();class ThreadA implements Runnable{Overridepublic void run() {System.out.println("Thread…

笔记本电脑word打字延迟特别大,但是浏览器中打字没有延迟,如何解决这个问题。

问题描述&#xff1a; 笔记本电脑word打字延迟特别大&#xff0c;但是浏览器中打字没有延迟&#xff0c;如何解决这个问题。&#xff08;之前以为是自己的电脑用了6年&#xff0c;用的时间久了&#xff0c;硬件老化导致的&#xff0c;本来想直接换电脑的&#xff0c;但是想着去…

鸿蒙前端开发-构建第一个ArkTS应用(Stage模型)

创建ArkTS工程 若首次打开DevEco Studio&#xff0c;请点击Create Project创建工程。如果已经打开了一个工程&#xff0c;请在菜单栏选择File > New > Create Project来创建一个新工程。 选择Application应用开发&#xff08;本文以应用开发为例&#xff0c;Atomic Serv…

数据库连接池Druid

在 Spring Boot 项目中&#xff0c;数据库连接池已经成为标配&#xff0c;然而&#xff0c;我曾经遇到过不少连接池异常导致业务错误的事故。很多经验丰富的工程师也可能不小心在这方面出现问题。 在这篇文章中&#xff0c;我们将探讨数据库连接池&#xff0c;深入解析其实现机…

探索开源游戏的乐趣与无限可能 | 开源专题 No.47

CleverRaven/Cataclysm-DDA Stars: 9.0k License: NOASSERTION Cataclysm&#xff1a;Dark Days Ahead 是一个回合制的生存游戏&#xff0c;设定在一个后启示录世界中。尽管有些人将其描述为 “僵尸游戏”&#xff0c;但 Cataclysm 远不止于此。在这个残酷、持久、程序生成的世…

抓取真实浏览器设备指纹fingerprint写入cookie方案

一个关于抓取真实浏览器设备指纹写入cookie方案&#xff0c;用户访问页面获取到用户设备生成指纹id&#xff0c;通过js把指纹存入cookie&#xff0c;然后用php进行获取cookie存的指纹值到后台。 用途&#xff1a;追踪用户设备&#xff0c;防恶意注册&#xff0c;防恶意采集 浏…