类加载过程介绍

news2024/11/29 8:55:23

489a0ff093964f2e9500ae6c42fec45d.jpg一、类的生命周期

 

 

类被加载到jvm虚拟机内存开始,到卸载出内存为止,他的生命周期可以分为:加载->验证->准备->解析->初始化->使用->卸载。

 

其中验证、准备、解析统一称为链接阶段

 

1、加载

 

  将类的字节码载入方法区中,内部采用 C++ 的 instanceKlass 描述 java 类,它的重要 field 有:

 

    _java_mirror 即 java 的类镜像,例如对 String 来说,就是 String.class,作用是把 klass 暴露给 java 使用

 

    _super 即父类

 

    _fields 即成员变量

 

    _methods 即方法

 

    _constants 即常量池

 

    _class_loader 即类加载器

 

    _vtable 虚方法表

 

    _itable 接口方法表

 

  如果这个类还有父类没有加载,先加载父类 加载和链接可能是交替运行的

 

2、链接

 

2.1验证

 

  验证是连接阶段的第一步,这一阶段的目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。验证阶段大致会完成4个阶段的检验动作:

 

  1)文件格式验证:验证字节流是否符合Class文件格式的规范;例如:是否以0xCAFEBABE开头、主次版本号是否在当前虚拟机的处理范围之内、常量池中的常量是否有不被支持的类型。

  2)元数据验证:对字节码描述的信息进行语义分析(注意:对比javac编译阶段的语义分析),以保证其描述的信息符合Java语言规范的要求;例如:这个类是否有父类,除了java.lang.Object之外。

  3)字节码验证:通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。

  4)符号引用验证:确保解析动作能正确执行。

 

验证阶段是非常重要的,但不是必须的,它对程序运行期没有影响,如果所引用的类经过反复验证,那么可以考虑采用-Xverifynone参数来关闭大部分的类验证措施,以缩短虚拟机类加载的时间。

 

2.2准备

 

  当完成字节码文件的校验之后,JVM 便会开始为类变量分配内存并初始化。这里需要注意两个关键点,即内存分配的对象以及初始化的类型。

 

内存分配的对象。Java 中的变量有「类变量」和「类成员变量」两种类型,「类变量」指的是被 static 修饰的变量,而其他所有类型的变量都属于「类成员变量」。

 

在准备阶段,JVM 只会为「类变量」分配内存,而不会为「类成员变量」分配内存。「类成员变量」的内存分配需要等到初始化阶段才开始。

 

例如下面的代码在准备阶段,只会为 factor 属性分配内存,而不会为 website 属性分配内存。

 

public static int factor = 3;

public String website = "www.baidu.com";

初始化的类型。在准备阶段,JVM 会为类变量分配内存,并为其初始化。但是这里的初始化指的是为变量赋予 Java 语言中该数据类型的零值,而不是用户代码里初始化的值。

例如下面的代码在准备阶段之后,sector 的值将是 0,而不是 3。

 

public static int sector = 3;

但如果一个变量是常量(被 static final 修饰)的话,那么在准备阶段,属性便会被赋予用户希望的值。例如下面的代码在准备阶段之后,number 的值将是 3,而不是 0。

 

public static final int number = 3;

2.3解析

 

  解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程,解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符7类符号引用进行。

 

符号引用:简单的理解就是字符串,比如引用一个类,java.util.ArrayList 这就是一个符号引用,字符串引用的对象不一定被加载。

直接引用:指针或者地址偏移量。引用对象一定在内存(已经加载)。

 

3、初始化

 

  初始化,这个阶段就是执行类构造器< clinit >()方法的过程,为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。

 

在Java中对类变量进行初始值设定有两种方式:

 

  声明类变量是指定初始值

  使用静态代码块为类变量指定初始值

JVM初始化步骤

  1)假如这个类还没有被加载和连接,则程序先加载并连接该类

  2)假如该类的直接父类还没有被初始化,则先初始化其直接父类

  3)假如类中有初始化语句,则系统依次执行这些初始化语句

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

  1)创建类的实例,也就是new的方式

  2)访问某个类或接口的静态变量,或者对该静态变量赋值

  3)调用类的静态方法

  4)反射(如Class.forName(“com.shengsiyuan.Test”))

  5)初始化某个类的子类,则其父类也会被初始化

  6)Java虚拟机启动时被标明为启动类的类(Java Test),直接使用java.exe命令来运行某个主类

 

不会导致类初始化的情况

  1)访问类的 static final 静态常量(基本类型和字符串)不会触发初始化

  2)类对象.class 不会触发初始化

  3)创建该类的数组不会触发初始化

 

4、使用

 

  当 JVM 完成初始化阶段之后,JVM 便开始从入口方法开始执行用户的程序代码。

 

5、卸载

 

  当用户程序代码执行完毕后,JVM 便开始销毁创建的 Class 对象,最后负责运行的 JVM 也退出内存。

 

二、类加载器

 

1、类加载器分类

 

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

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

  3)应用程序类加载器:Application ClassLoader,该类加载器由sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。

 

应用程序都是由这三种类加载器互相配合进行加载的,如果有必要,我们还可以加入自定义的类加载器。

 

2、双亲委派

 

 

 

 

 

 类加载器加载类的源码

 

复制代码

    protected Class<?> loadClass(String name, boolean resolve)

        throws ClassNotFoundException

    {

        synchronized (getClassLoadingLock(name)) {

            // 1. 检查该类是否已经加载

            Class<?> c = findLoadedClass(name);

            if (c == null) {

                long t0 = System.nanoTime();

                try {

                    if (parent != null) {

                        // 2. 有上级的话,委派上级 loadClass

                        c = parent.loadClass(name, false);

                    } else {

                        // 3. 如果没有上级了(ExtClassLoader),则委派BootstrapClassLoader

                        c = findBootstrapClassOrNull(name);

                    }

                } catch (ClassNotFoundException e) {

                    // ClassNotFoundException thrown if class not found

                    // from the non-null parent class loader

                }

 

                if (c == null) {

                    // If still not found, then invoke findClass in order

                    // to find the class.

                    long t1 = System.nanoTime();

                    // 4. 每一层找不到,调用 findClass 方法(每个类加载器自己扩展)来加载

                    c = findClass(name);

 

                    // this is the defining class loader; record the stats

                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);

                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);

                    sun.misc.PerfCounter.getFindClasses().increment();

                }

            }

            if (resolve) {

                resolveClass(c);

            }

            return c;

        }

    }

复制代码

 从图中我们发现除启动类加载器外,每个加载器都有父的类加载器。

双亲委派机制:如果一个类加载器在接到加载类的请求时,它首先不会自己尝试去加载这个类,而是把这个请求任务委托给父类加载器去完成,依次递归,如果父类加载器可以完成类加载任务,就成功返回;

 

只有父类加载器无法完成此加载任务时,才自己去加载。

 

 

 

从类的继承关系来看,ExtClassLoader和AppClassLoader都是继承URLClassLoader,都是ClassLoader的子类。而BootStrapClassLoader是有C写的,不再java的ClassLoader子类中。

从图中可以看到类加载器间的父子关系不是以继承的方式实现的,而是以组合关系的方式来复用父加载器的代码。

 

如果一个类加载器收到了类加载的请求,它首先会把这个请求委派给父加载器去完成,每一个层次的类加载器都是如此。

 

双亲委派模型的好处

  Java类随着加载它的类加载器一起具备了一种带有优先级的层次关系。比如,Java中的Object类,它存放在rt.jar之中,无论哪一个类加载器要加载这个类,最终都是委派给处于模型最顶端的启动类加载器进行加载,因此Object在各种类加载环境中都是同一个类。如果不采用双亲委派模型,那么由各个类加载器自己取加载的话,那么系统中会存在多种不同的Object类。

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蓝桥杯第十四届电子类单片机组程序设计

目录 前言 蓝桥杯大赛历届真题&#xff08;点击查看&#xff09; 一、第十四届比赛题目 1.比赛原题 2.题目解读 1&#xff09;任务要求 2&#xff09;注意事项 二、任务实现 1.NE555读取时机的问题 1&#xff09;缩短计数时间 2&#xff09;实时读取 2.温度传感器读…

unity的重中之重:组件

检查器&#xff08;Hierarchy&#xff09;面板中的所有东西都是组件。日后多数工作都是和组件打交道&#xff0c;包括调参、自定义脚本组件。 文章目录 12 游戏的灵魂&#xff0c;脚本组件13 玩转脚本组件14 尽职的一生&#xff0c;了解组件的生命周期15 不能插队&#xff01;…

专业130+总分420+厦门大学847信号与系统考研经验厦大信息系统与通信工程,真题,大纲,参考书。

今年很幸运被厦门大学录取&#xff0c;考研专业课847信号与系统130&#xff0c;数二130&#xff0c;总分420&#xff0c;回头看这将近一年的复习&#xff0c;还是有不少经验和大家分享&#xff0c;希望对大家复习有帮助。专业课&#xff1a; 厦门大学847信号与系统在全国各高校…

BossPlayerCTF

靶场环境问题 靶场下载之后&#xff0c;可能会出现扫描不到IP的情况&#xff0c;需要进行调整&#xff0c;参考&#xff1a; Vulnhub靶机检测不到IP地址_vulnhub靶机nmap扫不到-CSDN博客 该靶机没有vim&#xff0c;需要使用vi命令去修改&#xff1b;改成当前网卡即可&#x…

推荐《架构探险:从零开始写Java Web框架》

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 春节读了《架构探险&#xff1a;从零开始写Java Web框架》&#xff0c;一本大概10年前的好书。 本书的作者是阿里巴巴架构师黄勇。黄勇对分布式服务架构与大数据技术有深入…

【Linux】进程信号概念 | 核心转储 | 信号的产生

文章目录 一、信号入门1.1 生活中的信号1.2 进程角度的信号1.3 信号的概念1.4 信号的三种常见处理方式 二、信号的产生2.1 通过终端按键产生信号问题1&#xff1a;OS怎么知道键盘输入了ControlC &#xff1f;问题2&#xff1a;按CtrlC终止进程和按Ctrl\终止进程&#xff0c;有什…

多进程面试题汇总

这里写目录标题 一、多进程1、进程的定义&#xff1a;2、单核多任务CPU执行原理3、进程的优点和缺点4、创建进程15、创建进程26、进程池6.1、进程池的作用6.2、原理图6.3、使用进程池的优点 7、进程间的通信&#xff08;Queue&#xff09;7.1、需求1&#xff1a;采用多进程将10…

vue axios 请求后端无法传参问题

vue请求后端无法传参问题 问题描述处理过程总结 问题描述 在学习vue时&#xff0c;使用axios调用后端&#xff0c;发现无法把参数正确传到后端&#xff0c;现象如下&#xff1a; 使用vue发起请求&#xff0c;浏览器上已经有传参&#xff0c;但是后端没接收到对应的用户名密码&…

物流|基于Springboot的物流管理系统设计与实现(源码+数据库+文档)

物流管理系统目录 目录 基于Springboot的物流管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、管理员和管理员功能实现 &#xff08;1&#xff09;用户管理 &#xff08;2&#xff09;公告信息管理 &#xff08;3&#xff09;物流信息管理 &#xff08;…

希捷EXOS X 5U84存储数据恢复案例

一、案例背景 希捷EXOS X 5U84是一款高性能的企业级存储设备&#xff0c;常用于数据中心、云计算等领域。然而&#xff0c;即使使用最先进的存储设备&#xff0c;数据丢失的风险仍然存在。下面我们将介绍一起希捷EXOS X 5U84数据恢复案例。 天津某检测中心使用了希捷EXOS X 5U8…

【51单片机】利用STC-ISP软件工具【定时器计算器】配置【定时器】教程(详细图示)(AT89C52)

前言 大家好吖&#xff0c;欢迎来到 YY 滴单片机系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过单片机的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…

哈希切分

目录 一 二 三 2.单个子文件太大怎么办&#xff1f;&#xff08;分两种情况讨论&#xff09; 一 这样的题目典型就是KV模型的问题&#xff0c;即通过key IP找对应的value 出现次数&#xff0c;对于KV模型的问题首先想到的就是用map来统计次数&#xff0c;但是100G大小的文件…

《合成孔径雷达成像算法与实现》FIgure6.20

% rho_r c/(2*Fr)而不是rho_r c/(2*Bw) % Hsrcf exp函数里忘记乘pi了 clc clear close all参数设置 距离向参数设置 R_eta_c 20e3; % 景中心斜距 Tr 2.5e-6; % 发射脉冲时宽 Kr 20e12; % 距离向调频率 alpha_os_r 1.2; …

《合成孔径雷达成像算法与实现》Figure6.18

% rho_r c/(2*Fr)而不是rho_r c/(2*Bw) % Hsrcf exp函数里忘记乘pi了 clc clear close all参数设置 距离向参数设置 R_eta_c 20e3; % 景中心斜距 Tr 2.5e-6; % 发射脉冲时宽 Kr 20e12; % 距离向调频率 alpha_os_r 1.2; …

C++ bfs反向搜索(五十七)【第四篇】

今天我们来学习bfs的反向搜索。 1.反向搜索 反向搜索&#xff1a;是从目标状态出发进行的搜索&#xff0c;一般用于终点状态唯一&#xff0c;起点状态有多种&#xff0c;且状态转移是可逆的&#xff08;无向边&#xff09;情况。 例题&#xff1a;在一个长度为 n 的坐标轴上&a…

IDEA工程与模块管理

一、IDEA项目结构 层级关系&#xff1a; project(工程) - module(模块) - package(包) - class(类)具体的&#xff1a; 一个project中可以创建多个module一个module中可以创建多个package一个package中可以创建多个class二、Project和Module的概念 在 IntelliJ IDEA 中&…

round sphere around ground background space-around space-between space-evenly

round sphere around ground background space-around space-between space-evenly round around ground surround round sphere around ground background around surround around evenly between space-around space-between space-evenly Round: 描述形状为圆形或球形的。例…

Unity基础 -- 更新中(2.15)

Unity基础 文章目录 Unity基础3D数学 -- 基础一些方法插值运算三角函数坐标系 3D数学 -- 向量理解常用函数线性插值 3D数学 -- 四元数看向四元数计算 延迟函数协同程序 3D数学 – 基础 一些方法 float value01 Mathf.PI; // Π int value03 Mathf.Abs(-2); // 绝对值 int v…

OAuth 2.0 协议介绍【实现 GitHub 第三方登录】

OAuth&#xff08;是 Open Authorization 开放授权的缩写&#xff09;,在全世界得到广泛应用&#xff0c;目前的版本是2.0版。 本文会对OAuth 2.0的设计思路和运行流程&#xff0c;做一个简明通俗的解释&#xff0c;主要参考材料为RFC 6749。 OAuth 2.0 是一个开放标准&#…

Kubernetes安装部署 2

Kubeadm创建集群 如上所示&#xff0c;在阿里云的香港地域的ECS服务器上拉取下载Kubernetes官方提供的容器镜像 如上所示&#xff0c;在阿里云的香港地域的ECS服务器保存镜像到本地 Node A服务器的IP地址&#xff1a;192.168.0.130 端口号6443开放、部署Docker容器引擎、支持cr…