(一) 类加载过程详解 (类加载机制 第一篇)

article/2025/9/26 15:53:02

当我们用java命令运行某个类的main函数启动程序时,首先需要通过类加载器把主类加载到 JVM。

package com.shendu;public class JvmTest01 {public static final int initData = 666; public int compute() { int a = 1;int b = 2;int c = (a + b) * 10;return c;}public static void main(String[] args) {new JvmTest01().compute();}
}

如上面的代码:当我们用java命令运行某个类的main函数启动程序时,首先需要通过类加载器把主类加载到 JVM。

通过Java命令执行代码的大体流程如下:

在这里插入图片描述

以上就是整个从jvm到java中main程序的执行全部过程,main是所有程序的入口。

整个类加载如图所示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y9whTvuu-1636008372178)(C:\Users\ZUHAO.OUYANG\AppData\Roaming\Typora\typora-user-images\image-20211103172813056.png)]

加载

加载,是指Java虚拟机查找字节流(查找.class文件),并且根据字节流创建java.lang.Class对象的过程。这个过程,将类的.class文件中的二进制数据读入内存,放在运行时区域的方法区内。然后在堆中创建java.lang.Class对象,用来封装类在方法区的数据结构。

类加载阶段:

(1)Java虚拟机将.class文件读入内存,并为之创建一个Class对象。

(2)任何类被使用时系统都会为其创建一个且仅有一个Class对象。

(3)这个Class对象描述了这个类创建出来的对象的所有信息,比如有哪些构造方法,都有哪些成员方法,都有哪些成员变量等。

验证
验证阶段作用是保证Class文件的字节流包含的信息符合JVM规范,不会给JVM造成危害。如果验证失败,就会抛出一个java.lang.VerifyError异常或其子类异常。验证过程分为四个阶段:

文件格式验证:验证字节流文件是否符合Class文件格式的规范,并且能被当前虚拟机正确的处理。

元数据验证:是对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言的规范要求

字节码验证:主要是进行数据流和控制流的分析,保证被校验类的方法在运行时不会危害虚拟机。

符号引用验证:符号引用验证发生在虚拟机将符号引用转化为直接引用的时候,这个转化动作将在解析阶段中发生。

准备
准备阶段为变量分配内存并设置类变量的初始化。在这个阶段分配的仅为类的变量(static修饰的变量),而不包括类的实例变量。对已非final的变量,JVM会将其设置成“零值”,而不是其赋值语句的值:pirvate static int size = 12;。那么在这个阶段,size的值为0,而不是12。但final修饰的类变量将会赋值成真实的值。

解析
解析过程是将常量池内的符号引用替换成直接引用。主要包括四种类型引用的解析。类或接口的解析、字段解析、方法解析、接口方法解析。

初始化

初始化,则是为标记为常量值的字段赋值的过程。换句话说,只对static修饰的变量或语句块进行初始化。

如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。

如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。


类加载器和双亲委派机制

上面的类加载过程主要是通过类加载器来实现的,Java里有如下几种类加载器

  • 引导类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如 rt.jar、charsets.jar等
  • 扩展类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR 类包
  • 应用程序类加载器:负责加载ClassPath路径下的类包,主要就是加载你自己写的那 些类 自定义加载器:负责加载用户自定义路径下的类包

双亲委派机制

一个类只有被第一次主动使用时,才会被java虚拟机加载
主动使用的情况(6种)
1、创建类的实例
2、访问类的静态变量
3、调用类的静态方法
4、反射加载
5、初始化一个类的子类
6、java虚拟机启动时被标记为启动类的类

定义了几个类加载器。

  • AppClassLoader 系统类加载器 负责的目录如下:

    • %JAVA_HOME%/jre/lib
    • -Xbootclasspath 参数指定的目录
    • 系统属性sun.boot.class.path
  • ExtClassLoader 扩展类加载器 负责的目录如下:

    • %JAVA_HOME%/jre/lib/ext
    • 系统属性java.ext.dirs指定的类库
  • Bootstrap classLoader 启动类加载器 负责的目录如下:

    • 环境变量 classpath
    • -cp
    • 系统属性java.class.path

各个加载器的加载路径的验证

AppClassLoader 加载路径地址

        String appProperty = System.getProperty("java.class.path");for (String s : appProperty.split(";")) {System.out.println(s);}

打印为:

C:\Program Files\Java\jdk1.8.0_281\jre\lib\charsets.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\deploy.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\access-bridge-64.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\cldrdata.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\dnsns.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\jaccess.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\jfxrt.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\localedata.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\nashorn.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\sunec.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\sunjce_provider.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\sunmscapi.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\sunpkcs11.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext\zipfs.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\javaws.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\jce.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\jfr.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\jfxswt.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\jsse.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\management-agent.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\plugin.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\resources.jar
C:\Program Files\Java\jdk1.8.0_281\jre\lib\rt.jar
D:\tcl_ouyang\demo_coding\jvmclassload\target\classes
D:\tcl_ouyang\dev_soft\IntelliJ IDEA 2019.1.4\lib\idea_rt.jar

虽然打印了这么多的路径,但是其他的jar已经被它的父加载器给加载过了,根据双亲委托机制,其实AppClassLoader只是加载项目中的classpath路径下的类。

ExtClassLoader 加载路径

String extDirs = System.getProperty("java.ext.dirs");
for (String path : extDirs.split(";")) {
System.out.println(path);
}

打印

C:\Program Files\Java\jdk1.8.0_281\jre\lib\ext
C:\Windows\Sun\Java\lib\ext

Bootstrap classLoader加载路径

 URL[] urLs = sun.misc.Launcher.getBootstrapClassPath().getURLs();for (URL url : urLs) {System.out.println(url.toExternalForm());}

打印

file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/lib/resources.jar
file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/lib/rt.jar
file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/lib/sunrsasign.jar
file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/lib/jsse.jar
file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/lib/jce.jar
file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/lib/charsets.jar
file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/lib/jfr.jar
file:/C:/Program%20Files/Java/jdk1.8.0_281/jre/classes

我们在来验证下,各个加载器之间的关系

        System.out.println(JvmTest02.class.getClassLoader());System.out.println(JvmTest02.class.getClassLoader().getParent());System.out.println(JvmTest02.class.getClassLoader().getParent().getParent());

打印:

sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@1b6d3586
null

我们可以得出一个结论:AppClassLoader的父加载器是ExtClassLoader,然后我们的引导类加载器是不对外开放的,因为它是C++编写的,它不是一个类


JVM类加载器是有亲子层级结构的,如下图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IQ6CttY6-1636008372180)(C:\Users\ZUHAO.OUYANG\AppData\Roaming\Typora\typora-user-images\image-20211103173905907.png)]

这里类加载其实就有一个双亲委派机制,加载某个类时会先委托父加载器寻找目标类,找不到再 委托上层父加载器加载,如果所有父加载器在自己的加载类路径下都找不到目标类,则在自己的 类加载路径中查找并载入目标类。 比如我们的Math类,最先会找应用程序类加载器加载,应用程序类加载器会先委托扩展类加载 器加载,扩展类加载器再委托引导类加载器,顶层引导类加载器在自己的类加载路径里找了半天 没找到Math类,则向下退回加载Math类的请求,扩展类加载器收到回复就自己加载,在自己的 类加载路径里找了半天也没找到Math类,又向下退回Math类的加载请求给应用程序类加载器, 应用程序类加载器于是在自己的类加载路径里找Math类,结果找到了就自己加载了。。 双亲委派机制说简单点就是,先找父亲加载,不行再由儿子自己加载

为什么要设计双亲委派机制?

  • 沙箱安全机制:自己写的java.lang.String.class类不会被加载,这样便可以防止核心 API库被随意篡改 避免类的重复加载:

  • 当父亲已经加载了该类时,就没有必要子ClassLoader再加载一 次,保证被加载类的唯一性


http://chatgpt.dhexx.cn/article/O2CLFm46.shtml

相关文章

JVM(三):类加载机制(类加载过程和类加载器)

一、为什么要使用类加载器? Java语言里,类加载都是在程序运行期间完成的,这种策略虽然会令类加载时稍微增加一些性能开销,但是会给java应用程序提供高度的灵活性。例如: 1.编写一个面向接口的应用程序,可能…

类加载机制(类加载过程和类加载器)

一、为什么要使用类加载器? Java语言里,类加载都是在程序运行期间完成的,这种策略虽然会令类加载时稍微增加一些性能开销,但是会给java应用程序提供高度的灵活性。例如: 1.编写一个面向接口的应用程序,可能…

类加载的过程是怎样的?

写在前面 本文隶属于专栏《100个问题搞定Java虚拟机》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和文献引用请见100个问题搞定Java虚拟机 解答 JVM加载java类就是将字…

类加载(基本说明、流程图、类加载各个阶段完成的任务)

目录 基本说明 类加载过程流程图 类加载各阶段完成的任务 加载阶段 ​编辑 连接阶段-验证 连接阶段-准备 连接阶段-解析 Initialization(初始化) 类加载就是当字节码文件有了过后,进行下一步工作,不管是创建对象,还是干其…

什么是类的加载

一、什么是类的加载 java文件通过编译器变成了.class文件,接下来类加载器又将这些.class文件加载到JVM中。其中类装载器的作用其实就是类的加载。 其实,类加载器并不需要等到某个类被“首次主动使用”时再加载它,JVM规范允许类加载器在预料…

Windows下cmd命令—systeminfo

该命令是Windows中用于显示关于计算机及其操作系统的详细配置信息,包括操作系统配置、安全信息、产品 ID 和硬件属性,如 RAM、磁盘空间和网卡和补丁信息等。 例如:查看自己的计算机是32位还是64位 可以通过如下步骤: ①首先&…

SysInfoTools MS SQL Transaction Log Recovery 22.0

SysInfo DBF 修复工具专门用于修复由 dBase II IV、V Visual FoxPro、Clipper、dBXL、dBFast、CodeBase、MultiBase、Arago 生成的损坏、损坏和无法访问的 DBF 文件。从 SysInfoTools 下载最新和更复杂的基于 Windows 的应用程序 DBF 恢复实用程序,它可以一次性完美…

MASM32编程完善SysInfo遇到奇怪故障,真切感受全局变量和局部变量之别……

SysInfo主要是通过WMI来获取系统信息的,但是WMI获取的操作系统信息中没有Windows操作系统是32位还是64位的内容,所以需要另外想办法编程获取,比较常见的方法是调用Windows API函数GetNativeSystemInfo()或IsWow64Process()。之前分别用MASM32…

系统信息:uname,sysinfo,gethostname,sysconf

且欲近寻彭泽宰,陶然共醉菊花怀。 文章目录 系统信息系统标识 unamesysinfo 函数gethostname 函数sysconf()函数 系统信息 系统标识 uname 系统调用 uname()用于获取有关当前操作系统内核的名称和信息,函数原型如下所示(可通过"man 2 …

Django-搭建sysinfo获取系统信息

文章目录 前言一、项目搭建二、主机信息监控三、Celery定时任务和异步任务 前言 使用Django,搭建sysinfo,Linux中,sysinfo是用来获取系统相关信息的结构体 本篇基于:https://github.com/hypersport/sysinfo#readme项目借鉴路径: https://gi…

SysInfo(电脑系统信息)0.0.0.1beta2

文件说明符 : D:\masm32\wmi\sysInfo\sysInfo0.0.0.1beta2.exe 属性 : A--- 数字签名:否 PE文件:是 语言 : 中文(简体,中国) 文件版本 : 0.0.0001 beta2 说明 : 电脑系统信息 版权 : PurpleEndurer 产品版本 : 0.0.0001 beta2 产品名称 : 电脑系统信息 公司名称 : P…

sysinfo函数、结构体使用

1&#xff0c;头文件&#xff1a; #include <sys/sysinfo.h>2&#xff0c;函数声明&#xff1a; int sysinfo(struct sysinfo *info);3&#xff0c;返回值&#xff1a; 成功返回0&#xff0c;错误返回-1&#xff1b; 4&#xff0c;sysinfo结构体名称 Linux 2.3.23(i38…

Linux中sysinfo的用法

sysinfo结构体 Linux中,可以用sysinfo来获取系统相关信息。 Linux中,sysinfo是用来获取系统相关信息的结构体。 函数声明和原型&#xff1a; #include <sys/sysinfo.h> int sysinfo(struct sysinfo *info); 在Linux中不同对版本结构体不一样 在Linux 2.3.16中&#…

sysinfo 函数

在linux系统中&#xff0c;我们可以使用sysinfo()获取一些系统统计信息。我们在终端命令行中输入“man 2 sysinfo”即可获取sysinfo()的详细信息&#xff0c;如下图所示。 从上图可以知道&#xff0c;使用uname需要包含头文件"#include <sys/sysinfo.h>" sysi…

natapp

简介 natapp是一个内网穿透工具&#xff0c;内网穿透也叫做内网映射&#xff0c;也叫“NAT穿透”&#xff0c;所谓内网穿透简单来说就是让外网能够访问内网&#xff0c;即把自己的电脑当服务器&#xff0c;让别人能够访问自己的电脑。 使用 1、注册一个账号&#xff0c;并且进…

WAP PUSH

PUSH &#xff08;WAP-PUSH&#xff09;又叫做服务信息或推入信息&#xff0c;是一种特殊格式的短信。 目录 基本简介 特点优势 系统框架 推送协议 推送服务方式 短消息网关简介 基于短信网关发送WAP PUSH wapPDU 模式 分析 良好前景 基本简介 特点优势 系统框架 推送协议 推送…

睡眠 应该用 a加权 c加权_时间加权平均价格算法(TWAP)和成交量平均算法(VWAP)在量化回测的应用...

本应用实践平台为BigQuant人工智能量化平台 为什么要引入TWAP和 VWAP&#xff1f; 为了评估策略的资金容量&#xff0c;我们对M.trade模块里买入点和卖出点这两个参数进行了更丰富的扩展&#xff0c;支持了策略能够按更丰富的算法交易价格&#xff08;WAP&#xff09;进行撮合。…

【Java使用pushy(com.eatthepath)对接APns消息推送(基于HTTP/2协议)】

Java使用pushy(com.eatthepath)对接APns消息推送(基于HTTP/2协议) 需要IOS开发提供的信息 1.推送证书,.p8格式的文件 2.bundleId 3.keyId 4.teamId MAVEN依赖 <dependency><groupId>com.eatthepath</groupId><artifactId>pushy</artifactId>…

HTAP 简介

2019独角兽企业重金招聘Python工程师标准>>> HTAP的定义 数据库系统一般可以按照负载类型分成操作型数据库(Operational Support System)和决策型数据库(Decision Support System)。操作型数据库主要用于应对日常流水类业务,主要是面向消费者类的业务;决策型数…

爬取twitter数据--使用twint

最近因为实验验证的需要&#xff0c;想要爬取推特的数据&#xff0c;首先想到的是通过推特官方的开发者计划拿到key然后直接爬取&#xff0c;连接如下&#xff1a; twitter myapp 但是问题就在于&#xff0c;这玩意我用两个号申请都被拒绝了&#xff0c;据说是86的号码被拒就是…