JVM-类的加载机制

华为云Stack的学习(三) LVS是四层负载均衡,建立在OSI模型的传输层之上,所以效率非常高。NAT模式的转发主要通过修改IP地址(位于OSI模型的第三层网络层)实现转发。DR模式的转发主要通过修改MAC地址(位于OSI模型的第二层数据链路层)实现转发。云服务框架中使用的DR模式。域名解析服务器分为管理侧(OM)和租户侧(Tenant)**DNS-OM:**作为云服务的本地DNS服务器,为云服务提供域名解析服务,并代理公网域名的解析。 阅读详情

概述

虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始
化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。

类加载时机:

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载
(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化
(Initialization)、使用(Using)和卸载(Unloading)7个阶段。其中验证、准备、解析3个
部分统称为连接(Linking).
在这里插入图片描述

在加载阶段:JVM规范中没有进行约束, 这点可以交给虚拟机的具体实现来自由把握.
在初始化阶段:
JVM严格规范了有且只有以下5种情况必须立即进行初始化(初始化前,必须经过加载,验证解析,准备阶段)
1.使用new实例化对象时,读取(getstatic)和设置(putstatic)类的静态变量,静态非字面值常量时,调用静态方法(invokestatic)时
2.对内进行反射调用时, 如果类没有进行过初始化,则需要先触发其初始化
3.当初始化一个类时,如果父类没有进行初始化,首先要初始化父类.
4.启动程序所使用的main方法所在类
5.当使用1.7的动态语言支持时
以上5种称为主动引用,除此之外的引用被称为被动引用

被动引用常见情况:

  • 调用父类的静态字段,只会初始化父类,不会触发子类的初始化
  • 定义对象数组和集合,不会触发该类的初始化
  • 类A引用类B的static final 常量不会导致类B初始化(注意静态常量必须是字面值常量,否则还是会触发B的初始化)
  • 通过类名获取对象,不会触发类的初始化(System.out.println(Person.class));
  • 通过Class.forName加载指定类时,如果指定参数initialize为false,也不会初始化该类
  • 通过ClassLoader默认的loadClass方法,也不会触发初始化.

类加载过程:

加载流程: 加载->连接(验证->准备->解析)->初始化->使用->卸载

加载

在加载阶段 , JVM需要完成3件事情

  1. 查找并加载类的二进制数据(Class文件)
  2. 静态存储结构转化为方法区运行时数据结构:类的类信息
  3. Java堆生产:Class文件对应的类实例(相当于一个句柄),去访问方法区

加载.class文件的方式:

  • 从本地系统中直接加载
  • 通过网络下载class文件
  • 将java源文件动态编译为.class文件
  • …

验证

确保加载的类信息是正确的

  • 文件格式验证
    • 验证Class文件的标示:魔数(默认为:CAFE BABE)
    • 验证Class文件的版本号
    • 验证常量池(常量类型,常量类型数据结构是否正确,UTF8是否符合标准)
    • Class文件的每个部分(字段表,方法表)是否正确
  • 元数据验证(父类验证,继承验证,接口验证,final验证)
    • 这个类是否有父类,是否实现了父类的抽象方法,是否重写了父类的final方法,是否继承了被final修饰的类等等
  • 字节码验证(指令验证)
  • 符号引用验证(通过符号引用是否能找到类,方法,字段)
    • 通过符合引用能找到对应的类和方法
      ,符号引用中类、属性、方法的访问性是否能被当前类访问等等。

准备

类变量:一般称为静态变量
实例变量:当对象被实例化时,实例变量就被跟着被确定

为类的静态变量(static)分配内存空间并赋予初始值(默认值) ,这些变量所使用的内存都将在方法区中进行分配.

例:static int value = 2;初始化值为0.

这时候尚未开始执行任何Java方法,而把value赋值为2的putstatic指令是程序被编译后,存放于类构造器< clinit>()方法之中,所以把value赋值为2的动作将在初始化阶段才会执行。

而 static final int value = 2;

对应到常量池ConstantValue,在准备阶段必须赋值为2.

数据类型对应的零值
基本数据的零值

解析

将符号引用转化为直接引用
直接引用: 指向目标的指针或者偏移量
主要涉及:类,接口,字段,方法等.
匹配:简单名字+描述符 同时满足

类或接口的解析

public class A{
	C data; //C有可能是个类,或接口
}
  1. 如果C不是一个数组类型 , 那么会将代表N的权限定名传递给A去加载这个类C . 若在加载C的过程中出现了异常,则解析失败.
  2. 如果C是一个数组类型 ,并且数组元素类型为对象 (Integer[] data), 则按照 1中的方式先加载数组元素类型 ,接着由虚拟机生成一个代表此数组维度和元素的数组对象.
  3. 如果上面的步骤没有出现任何异常,那么C在虚拟机中实际上已经成为一个有效的类或接口了,但在解析完成之前还要进行符号引用验证,确认A是否具备对C的访问权限。

如果发现不具备访问权限,将抛出java.lang.IllegalAccessError异常。

字段的解析:

class A extends B implements C,D{
     private int a;  
}
  1. 先在本类去找有没有简单名称和字段描述符匹配的字段,有则返回字段的引用 , 查找结束.
  2. 如果类实现了接口,递归搜索各个接口和它的父接口,如果接口中包含了简单名称和字段描述符都与目标相匹配的字段,则返回这个字段的直接引用,查找结束.
  3. 如果不是继承Object类, 再去搜索父类 , 有则返回.
  4. 否则 , 查找失败

查找可能会有异常

如果找到,没有权限:java.lang.IllegalAccessError 如果失败:java.lang.NoSuchFieldError

类方法的解析:

class A extends B implements C,D{
     public void inc();
}

类方法和接口方法符号引用的常量类型定义是分开的,如果在类方法表中发现class_index中索引的C是个接口,那就直接抛出java.lang.IncompatibleClassChangeError异常。

  1. 在本类里面去找有没有匹配的方法
  2. 父类去找
  3. 接口列表去找方法(如果找到则代表本类是抽象类)

如果找到,没有权限:java.lang.IllegalAccessError 如果失败:java.lang.NoSuchMethodError

接口方法的解析:
与类方法解析不同,如果在接口方法表中发现class_index中的索引C是个类而不是接口,那就直接抛出java.lang.IncompatibleClassChangeError异常。

  1. 在本类找有没有匹配的方法
  2. 父类接口去递归查找

如果失败:java.lang.NoSuchMethodError
由于接口中的所有方法默认都是public的,所以不存在访问权限的问题,因此接口方法的符号解析应当不会抛出java.lang.IllegalAccessError异常。

初始化

java虚拟机对类进行初始化,对静态变量赋予正确值, 真正开始执行类中定义的Java程序代码.
< init>:类的实例构造器
< clinit>:由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并.(如果没有静态变量,静态块,则没有clinit)

在类中:

< clinit>()方法与类的构造函数(或者说实例构造器< init>()方法)不同,它不需要显式地调用父类构造器,虚拟机会保证在子类的<
clinit>()方法执行之前,父类的< clinit>()方法已经执行完毕。因此在虚拟机中第一个被执行的<
clinit>()方法的类肯定是java.lang.Object。 由于父类的<
clinit>()方法先执行,也就意味着父类中定义的静态语句块要优先于子类的变量赋值操作,

在接口中:

接口中不能有静态块 ,但仍然有变量初始化的赋值操作,因此接口与类一样都会生成< clinit>()方法。
但接口与类不同的是,执行接口的< clinit>()方法不需要先执行父接口的< clinit>()方法。只有当父接口中定义的变量使用时,父接口才会初始化。另外,接口的实现类在初始化时也一样不会执行接口的< clinit>()方法。

虚拟机会保证一个类的< clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的< clinit>()方法,其他线程都需要阻塞等待,直到活动线程执行< clinit>()方法完毕 .

Class A{
    static int i = 2;
    static{
          sout;
     }
    int n;
}

类的加载方式(整个过程)

隐式加载

  • 创建类对象
  • 使用类的静态域
  • 创建子类对象
  • 使用子类的静态域

在JVM启动时,BootStrapLoader会加载一些JVM自身运行所需的class
在JVM启动时,ExtClassLoader会加载指定目录下一些特殊的class
在JVM启动时,AppClassLoader会加载classpath路径下的class,以及main函数所在的类的class文件

显式加载

ClassLoader.loadClass(className),只会加载和链接,不会进行初始化
Class.forName(String name,boolean initialize,ClassLoader loader),使用loader进行加载和链接,根据initialize参数决定是否初始化

类加载器:

对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立其在Java虚拟机中的唯一性 , 每一个类加载器,都拥有一个独立的类名称空间。在比较两个类是否“相等”时 ,只有在这两个类是由同一个类加载器加载的前提下才有意义,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机加载,只要加载它们的类加载器不同,那这两个类就必定不相等。

//sun.misc.Launcher
//..........
/..........
var1 = Launcher.ExtClassLoader.getExtClassLoader();
this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
//..........

问题: ExtClassLoader和AppClassLoader有什么关系?

ExtClassLoader是AppClassLoader的Parent

//代表同时只有一个load来加载class,保证class的唯一性
findBootStrapClass(String name):  //方法
synchronized(getClassLoadingLock(name)) {
    Class<?> c = findLoadedClass(class);
    if(c == null) {
          ......
          if(parent != null) {
                 //递归调用
           } else {
                  findBootStrapClass(name);  //native方法 JNI调用
            }
     }
}
  • BootStrapClassLoader(C语言编写): JAVA_HOME
    /lib/rt.jar
  • ExtClassLoader: JAVA_HOME/lib/ext/javax.* 或"java.ext.dirs"指向的目录
  • AppClassLoader:自定义的类,负责将系统类路径(CLASSPATH)中指定的类库加载到内存中
  • 用户自定义类加载器: 流,网络,数据库

双亲委派机制(安全)

在这里插入图片描述
如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把请求委托给父类加载器去完成,依次向上.因此,所有的类加载请求最终都会被传递到顶层的启动类加载器中.
只有当父加载器在他的搜索范围中没有找到所需的类时,既无法完成加载,自加载器才会尝试自己去加载该类.
父类能加载的,不给子类加载

这种机制有如下好处:

  • 可以保证java核心类库的安全,即保证由引导类加载器加载的类不能被用户随便替换,不能自己定义一个java.lang.String 的类来替换java核心类库的java.lang.String类,否则会抛出ClassCastException。
  • 避免类的重复加载.

加载顺序: 自顶向下 AppClassLoader -> Extension ClassLoader -> BootStrap ClassLoader
检查顺序: 自底向上

YOLOv11-Pose部署RK3588实战:人体姿态识别精度翻倍,边缘推理速度突破瓶颈 本教程从YOLOv11-pose模型的姿态识别训练,到RK3588的边缘量化部署,为你打造了一套“高精度+高实时性+低成本”的人体姿态分析解决方案。无论是健身动作纠正、智能安防行为检测,还是工业人员姿态监控,这套技术都能直接复用——你只需替换数据集与业务逻辑,即可快速落地专属的边缘AI姿态识别系统。如果你在实践中遇到任何卡点,欢迎随时交流。记住,人体姿态识别的价值在于“关键点准、推理快、部署易”,而这三者的平衡,正是你通过本教程能掌握的核心能力。 阅读详情

相关推荐

webrtc获取IceCandidate流程

foundation:用于唯一标识候选者的基础信息,通常是基于候选者的类型、IP地址、协议和replay协议计算出的字符串。component:标识候选者所属的传输组件。对于RTP流,通常使用1;对于RTCP流,通常使用2。protocol:候选者使用的传输协议,通常是UDP,但也可以是TCP(尽管在WebRTC中UDP更为常见)。priority:候选者的优先级,用于在选择最佳候选对时进行比较。优先级的计算公式考虑了候选类型优先级、本地优先级和组件ID。address:候选者的IP地址。port。

qq_42805085的博客 1901

Class.forName() 与 ClassLoader.loadClass() 的区别

Class.forName() 的方式加载类时,默认会执行类的初始化。ClassLoader.loadClass() 的方式加载类时,类不会被初始化,只有显式调用加载的类时才会进行初始化。采用 ClassLoader 进行懒加载,不会调用类的 static 代码块,实现延迟加载。

JellyfishMIX 的博客 795

深度强化学习算法PPO训练Pendulum

returnadv = 0print('状态空间维度:', state_n)print('动作空间维度:', action_n)steps = []if done:breakif done:breakelse:steps = []if done:break。

weixin_43336108的博客 808

jvm中变量的存放位置

(如果局部变量是一个reference引用类型,它引用的对象在Java堆中可被各个线程共享,但是reference引用本身在Java栈的局部变量表中,是线程私有的)。Java内存模型的主要目标是定义程序中各个变量的访问规则,即在JVM中将变量存储到内存和从内存中取出变量这样的底层细节。而类的方法却是该类的所有对象共享的,只有一套,对象使用方法的时候方法才被压入栈,方法不使用则不占用内存。类的成员变量在不同对象中各不相同,都有自己的存储空间(成员变量在堆中的对象中)。对象在堆里,对象中的内容就是各种字段。..

m0_67401055的博客 1419

(蓝桥杯)STM32G431RBT6(SysTick timer)

选用最基础的定时器。

2301_81764359的博客 1903

OCCT(Open CASCADE Technology)入门-2.搭建开发环境

安装完成后,在【扩展】菜单下会看到【Qt VS Tools】菜单,打开子菜单【options】进入qt配置窗口。打开VS后随便创建一个新项目,进入开发环境主页,打开顶部菜单【扩展】->【管理扩展】打开管理扩展窗口。然后点击右下角【创建】,一路【next】即可,最后会进入到开发主界面,得到一个下面的工程结构。好了,到这里基本的环境我们已经安装好了,下面我们开始创建项目并配置开发环境。打开顶部菜单【项目】,点击最后一个菜单项【xxx属性】,进入项目配置界面。这里的配置一般不用改,我们看【Versions】

2501_91235145的博客 2876

JVM-类加载详解

一、JVM类加载过程 JVM类加载过程如下图: JVM类加载过程分为:加载 、链接 、初始化 、使用 、卸载 这五个阶段,其中链接阶段又包括: 验证 、 准备 、 解析 。 加载 :通过类的完全限定名,查找此类的二进制字节码文件,通过该字节码文件创建Class对象。 链接 :包含 验证 、 准备 、 解析 三个阶段: 验证 :确保Class文件复合虚拟机规定的Class文件格式,包含文件格式验证、元数据验证、字节码验证、引用符号验证。 准备 :为类的静态变量分配内存并设置初始化值,注:这里不包含fi

qq_34222160的博客 9038

基于Super-Jacoco的精准测试实践之路

灵魂拷问这个版本的影响范围到底有多大?研发改动了代码,为什么不通知测试?测试用例真的全面覆盖了吗?测试同学的测试覆盖情况该怎么评估?什么是精准测试概念借助技术手段、通过辅助算法对软件测试过...

咻咻ing的专栏 5842

类的成员变量存在JVM的哪块区域

public class A{ public static void main(String[] args){ B b = new B(); } } public class B{ int i; C c; B(){ i = 1; c = new C(); } } public class C{ } 记住一个原则即可:方法体中的引用变量和基本类型的变量都在栈中,其他的都在堆中。 所以B对象里面的所有东

weixin_46314604的博客 1730

ResNet改进(20):融合Swin Transformer与ResNet

这种混合架构的设计理念是:在保留CNN强大局部特征提取能力的同时,引入Transformer的全局建模优势。我们实现的模型在ResNet18的基础上嵌入了一个简化版的Swin Transformer Block,旨在探索两种范式结合的可能性。通过在ResNet早期阶段引入Transformer模块,我们既保留了CNN强大的局部特征提取能力,又获得了Transformer的全局建模优势。本文提出的ResNet与Swin Transformer混合架构,探索了CNN与Transformer结合的可能性。

2401_82355416的博客 859

【JVM】——类的加载机制

一、什么是类的加载 (1)类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。 (2)类加载器并不需要等到某个类被...

我爱吃土豆 8510

RK3568适配MIPI屏幕触摸,触摸延时很大

我用的是系统,接了一个,设备树已经正确配置,evtest测试坐标值和触摸位置都是准确的。但是出现了一个:我在屏幕上点一下,要等大约 2 秒才能在evtest里看到坐标事件打印。这种现象在 Goodix 系列触摸驱动里比较少见,一般意味着。

小灰灰的博客 1363

JVM类的加载机制

在学习之前,我们现象几个问题: 1.JVM的类加载机制是什么? 2.它是如何实现的其功能的? 3.在什么情况下在使用类加载器? 带着这几个问题,我们一步一步深入学习一下。 一、什么是类加载机制? 虚拟机把描述类的数据,从class文件(即一组以8位字节为基础单位的二进制流)加载到内存中,并对数据进行各种处理,最终生成能够直接被虚拟机识别的Java类型; 它分为以下几个...

许我笔墨三千绘你绝世倾城 303

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

【JVM】类的加载机制

JVM类加载机制是Java程序运行的核心过程,主要包括加载、验证、准备、解析和初始化五个阶段。加载阶段通过类加载器获取二进制字节流并转换为运行时数据结构;验证确保字节码符合规范;准备为静态变量分配内存并设置初始值;解析将符号引用转为直接引用;初始化执行类构造器方法完成程序逻辑初始化。类加载器采用双亲委派模型,确保类唯一性和程序稳定性,但也存在三次典型"破坏"以解决兼容性、SPI调用和热部署等需求。整个过程严格规范类加载顺序,同时保留灵活性以适应不同应用场景。

2501_91676654的博客 911

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

【JVM基础】 JVM 如何加载一个类以及类加载机制

如果你要 “new ReplicaManager()” 初始化这个类的实例,那么就会加载这个类,然后初始化这个类,但是初始化这个类之前,发现 AbstractDataManager 还没有加载和初始化,就需要先加载这个父类,并且初始化这个父类。然后从 main 方法的入口代码开始。假设你的应用程序需要去加载一个类,他首先会委派给自己的父类加载器去加载,经过层层床底,最终传递到顶层的类加载器去加载。但是如果父类加载器在自己负责范围加载的范围内没有找到这个类,就会将加载的权利给自己的子类加载器去进行加载。

【程序员不弃】的博客 1964

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

jvm类加载机制_JVM类的加载机制

1.概述虚拟机加载Class文件(二进制字节流)到内存,并对数据进行校验、转换解析和初始化,最终形成可被虚拟机直接使用的Java类型,这一系列过程就是类的加载机制。2.类的加载时机类从被虚拟机加载到内存开始,直到卸载出内存为止,整个生命周期包括:加载——验证——准备——解析——初始化——使用——卸载这7个阶段。其中验证、准备、解析3个部分统称为连接。生命周期图如下:  其中加载、验证、...

weixin_39764494的博客 79

JVM——类的加载机制

JVM将class字节码加载到内存中,将数据

雪人奥特曼的博客 257

类重复引用_JVM类加载机制

JVM类加载机制1、整体流程:2、加载扩展类加载器以及应用类加载器JVM自动调用getLauncher()方法获取launcher实例,而Launcher实例是在引导类加载器加载Launcher类的“初始化”阶段进行实例化的(launcher属性被static修饰)。下面看一下Launcher类的构造方法,可以看到Launcher类是如何加载扩展类加载器以及应用类加载器的:首先创建扩展类...

weixin_34562922的博客 724

JVM类加载机制-类是如何被加载的?

JVM把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被JVM直接使用的Java类型,这就是JVM的类加载机制类的生命周期JVM规范中初始化的条件被动引用不会触发初始化类加载的过程加载:非数组类:数组类:验证文件格式验证元数据验证字节码验证符号引用验证准备解析初始化 类的生命周期 加载、验证、准备、初始化和卸载5个阶段的顺序是确认的,类加载过程必须按照这种顺序按部就班的开始,在动态绑定中解析可以在初始化后完成 JVM规范中初始化的条件 使用new关键字实例化对象

qq_24760259的博客 869

【JVM】JVM类的加载机制(详解)

类从加载到卸载,整个生命周期统共分为7个阶段: 其中,加载->验证->准备->解析->初始化,这5个过程就是类的加载过程,而且验证->准备->初始化这三个可以统称为连接过程; 解析阶段有时候会在初始化之后再开始; 那么,什么时候会触发类的加载? 1⃣️ main()所在的主类; 2⃣️ 在遇到new、要对某个类的静态变量进行get或set、或者调用它的静态方法时; 3⃣️ 对某个类使用反射时; 4⃣️ 已经在对某个类进行加载,并且进行到初始化阶段时,而它的父..

卷柏的博客 390

JVM虚拟机加载类原理机制

<br />JVM虚拟机加载类原理机制

liu1695347的专栏 543

反射、 Class类、JVM的类加载机制、Class的常用方法

反射、 Class类、JVM的类加载机制、Class的常用方法

hutao8896的博客 1192

JVM--类的加载机制

本文介绍JVM中类加载器的种类和类加载机制(双亲委派)以及JDK9以后的类加载器的变化由不同的类加载器解析相同路径下的类信息得到的类对象不会相同Tomcat:在Tomcat中启动了两个Web服务,这两个服务有着相同的类名不同实现的实现类,此时如果不打破双亲委派机制,先启动的Web服务就会去加载好对应的类,那么后启动的Web服务在自下而上查询类是否被加载过时,就会直接返回先启动服务的类对象那么Tomcat如何打破双亲委派机制呢?给每个服务都专门弄一个类加载器。

nobestnobest的博客 1030
上一篇: JVM-内存分配策略和垃圾回收策略
下一篇: 集合-ArrayList源码分析
Java-fly
博客等级 码龄9年 13粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值