【小记】探析Java类加载时机

Java虚拟机_JVM_参数配置 NULL 博文链接:https://robinjoe.iteye.com/blog/1186847 立即下载

2021-09-14

最近在重温《深入理解Java虚拟机》这本书,对于第七章的类加载机制部分了解到了之前没有注意的细节,特在此总结记录下来。


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

什么情况下需要开始类加载过程的第一个阶段:加载?Java虚拟机规范中并没有进行强制约束,这点可以交给虚拟机的具体实现来自由把握。但是对于初始化阶段,虚拟机规范则是严格规定了有且只有5种情况必须立即对类进行“初始化”(而加载、验证、准备自然需要在此之前开始)

五种情况

  • 遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令的最常见的Java代码场景是:使用new关键字实例化对象的时候、读取或设置一个类的静态字段(被final修饰、已在编译期把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。
  • 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
  • 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
  • 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机回先初始化这个主类。
  • 当使用JDK1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。

对于这5种会触发类进行初始化的场景,虚拟机规范中使用了一个很强烈的限定语:“有且只有”,这5种场景种的行为称为对一个类进行主动引用。除此之外,所有引用类的方式都不会触发初始化,称为被动引用。下面举3个例子来说明何为被动引用。

被动引用的例子1
package org.fenixsoft.classloading

/**
 * 被动使用类字段例1;
 * 通过子类引用父类的静态字段,不会导致子类初始化
 **/
public class SuperClass {
	static {
		System.out.println("SuperClass init!");
	}
	public static int value = 123;
}

public class SubClass extends SuperClass {
	static {
		System.out.println("SubClass init!");
	}
}

public class NotInitialization {
	public static void main(String[] args) {
		System.out.println(SubClass.value);
	}
}

上述代码运行之后,只会输出“SuperClass init!”,而不会输出“SubClass init!”。对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过其子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。至于是否要触发子类的加载和验证,在虚拟机规范中并未明确规定,这点取决于虚拟机的具体实现。对于Sun HotSpot虚拟机来说,可通过-XX:+TraceClassLoading参数观察到此操作会导致子类的加载。

被动引用的例子2
package org.fenixsoft.classloading

/**
 * 被动使用类字段例2
 * 通过数组定义来引用类,不会触发此类的初始化
 */
public class NotInitialization {
	public static void main(String[] args) {
		SuperClass[] sca = new SuperClass[10];
	}
}

这段代码复用了例1,运行之后发现没有输出“SuperClass init!”,说明并没有触发类org.fenixsoft.classloading.SuperClass的初始化阶段。但是这段代码里面触发了另外一个名为Lorg.fenixsoft.classloading.SuperClass的类的初始化阶段,对于用户代码来说,这并不是一个合法的类名称,它是一个由虚拟机自动生成的、直接继承于java.lang.Object的子类,创建动作由字节码指令newarray触发。

这个类代表了一个元素类型为org.fenixsoft.classloading.SuperClass的一维数组,数组中应有的属性和方法(用户可直接使用的只有被修饰为public的length属性和clone()方法)都实现在这个类里。Java语言中对数组的访问比C/C++相对安全是因为这个类封装了数组元素的访问方法,而C/C++直接翻译为对数组指针的移动。在Java语言中,当检查到发生数组越界时会抛出java.lang.ArrayIndexOutOfBoundException异常。

被动引用的例子3
package org.fenixsoft.classloading

/**
 * 被动使用类字段例3
 * 常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。
 */
public class ConstClass {
	static {
		System.out.println("ConstClass init!");
	}
	public static final String HELLOWORLD = "hello world";
}
/**
 * 非主动使用类字段演示
 **/
public class NotInitialization {
	public static void main(String[] args) {
		System.out.println(ConstClass.HELLOWORLD);
	}
}

上述代码运行之后,也没有输出“ConstClass init!”,这是因为虽然在Java源码中引用了ConstClass类中的常量HELLOWORLD,但其实在编译阶段通过常量传播优化,已经将此常量的值“hello world”存储到了NotInitialization类的常量池中,以后NotInitialization对常量ConstClass.HELLOWORLD的引用实际都被转化为NotInitialization类对自身常量池的引用了。也就是说,实际上NotInitialization的Class文件之中并没有ConstClass类的符号引用入口,这两个类在编译成Class之后就不存在任何联系了。

接口的加载过程与类加载过程稍有些不同。针对接口需要做一些特殊说明:接口也有初始化过程,这点与类是一致的,上面的代码都是用静态语句块“static{}”来输出初始化信息的,而接口中不能使用“static{}”语句块,但编译器仍然会为接口生成“()”类构造器,用于初始化接口中所定义的成员变量。接口与类真正有所区别的是前面讲述的5中“有且仅有”需要开始初始化的场景中的第3种:当一个类在初始化时,要求其父类全部都已经初始化过了,但是一个接口在初始化时,并不要求其父接口全部都完成了初始化,只是在真正使用到父接口的时候(如引用接口中定义的常量)才会初始化。

YOLOv8轻量化模型瘦身术:深度解析与实战LAMP剪枝 YOLOv8(2021) YOLOv8模型LAMP剪枝技术解析与实战 本文深入探讨了LAMP剪枝技术在YOLOv8目标检测模型中的应用。针对深度学习模型部署面临的资源限制问题,LAMP剪枝通过最小化L2失真和层自适应稀疏度分配,实现了高效模型压缩。相比传统幅度剪枝的"一刀切"方法,LAMP创新性地将剪枝建模为优化问题,定义LAMP分数来衡量权重重要性,自动确定各层最佳剪枝率。文章从理论基础出发,详细解析了LAMP的核心数学公式和算法流程,并提供了完整的YOLOv8移植实战指南,包括代码结构、剪枝步骤和微调策略。通 阅读详情

相关推荐

An example: 2D immersed boundary lattice Boltzmann method code--By Timm Krüger.2011.

//谢谢Timm Krüger大佬的代码。 还是老样子,有啥问题Feel free to tell us~毕竟群众力量大嘛~QQ群:293267908。 // 话不多说,上干货! // ISBN 978-3-319-44649-3 (Electronic) // 978-3-319-44647-9 (Print) // http://www.springer.c...

weixin_37783345的博客 1418

JVM系列教程:1、类的加载

JVM深入理解-1、jvm初识jvm介绍hotspot虚拟机详解类加载器功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 jvm介绍 jvm是一个令人望而却步的领域,因为它很博大精深,涉及到的内容与知识点非常之多,虽然java开发者

weixin_43968821的博客 1763

Day470&471.Netty概述&Netty高性能架构设计 -netty

Netty概述 一、原生 NIO 存在的问题 NIO 的类库和 API 繁杂,使用麻烦:需要熟练掌握 Selector、ServerSocketChannel、SocketChannel、ByteBuffer等。 需要具备其他的额外技能:要熟悉 Java 多线程编程,因为 NIO 编程涉及到 Reactor 模式,你必须对多线程和网络编程非常熟悉,才能编写出高质量的 NIO 程序。 开发工作量和难度都非常大:例如客户端面临断连重连、网络闪断、半包读写、失败缓存、网络拥塞和异常流的处理等等。 JDK NIO

阿昌爱Java 1572

-XX:+TraceClassLoading和-XX:+TraceClassUnloading

顾名思义,-XX:+TraceClassLoading和-XX:+TraceClassUnloading这两个参数可以跟踪类加载和卸载的情况。 这两个参数有什么使用思路? 如果碰到经常Full GC的情况,但是老年代空间使用的却不多,年轻代GC后的情况也很正常,同时也不存在突然大对象的情况,但是元空间却一直递增,那么可以考虑下是不是使用了反射等手段导致元空间加载的类太多了,导致元空间爆满触发Full GC,那么此时就可以加上-XX:+TraceClassLoading和-XX:+TraceClassUn

硅脂味咖啡的博客 4275

ESP32-S3双模CMSIS-DAP调试器:USB+WiFi无线调试方案

CMSIS-DAP是ARM生态中标准化的嵌入式调试协议接口,广泛用于Keil、IAR、STM32CubeIDE等开发环境。其核心原理是通过SWD/JTAG物理层实现目标芯片寄存器访问、内存读写与断点控制,依赖确定性时序和低延迟通信。传统DAPLink调试器受限于USB线缆束缚,而WiFi-USB-DAPLink项目将完整CMSIS-DAP v2协议栈移植至ESP32-S3平台,同时支持USB CDC直连与WiFi TCP远程通道,兼顾实时性与网络化部署能力。该方案无需主机驱动、兼容主流IDE,并支持多机并发

weixin_31185473的博客 369

C++跨平台Word文档处理库DuckX实战指南:从原理到项目集成

在C++开发中,处理Office文档,尤其是Word文件,常因缺乏原生易用的库而面临挑战。Office Open XML(OOXML)作为.docx文件的基础标准,其本质是包含XML文件的ZIP压缩包。理解这一原理,开发者便能通过解析和操作XML来实现文档的读写。DuckX库正是基于此,为C++提供了轻量级的解决方案。它封装了底层的ZIP处理和XML解析,提供了简洁的面向对象API,其技术价值在于实现了跨平台、无外部依赖的Word文档自动化生成与处理。这尤其适用于服务器端、嵌入式环境或需要脱离Office软

weixin_33508411的博客 387

JVM:打印类加载过程的参数

设定vm 参数: -XX:+TraceClassLoading "C:\Program Files\Java\jdk1.8.0_202\bin\java.exe" -XX:+TraceClassLoading "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.1\lib\idea_rt.jar=10654:C:\Program Files\JetBrains\IntelliJ IDEA 2018.2.1\bin" -Dfile.encod

amadeus_liu2的博客 1790

华为OD技术面真题 - Python开发 - 1

汇总华为OD技术面八股Python八股,高频技术真题并提供详细解答。

qq_45776114的博客 1719

JVM调优

jvm工具 jps 显示系统中所有Hotspot虚拟机进程 jstat 收集Hotspot虚拟机各方面运行数据 jstack 显示虚拟机的线程栈信息 jinfo 显示虚拟机的配置信息 jmap 用于生成虚拟机的内存快照信息 jvm内存结构 左边蓝色是虚存(应用运行时额外使用的内存,主要是系统级线

jaryle的专栏 1410

梯度提升决策树GBDT原理与代码实例讲解

梯度提升决策树GBDT原理与代码实例讲解 1.背景介绍 1.1 机器学习发展历程 机器学习是人工智能领域的一个重要分支,旨在使计算机具备学习和改进自身性能的能力。随着大数据时代的到来,海量的数据为机器学习算法提供了广阔的应用空间。在

AI天才研究院 1089

DDR5 输入时钟抖动规范全解析!技术宅必看

简单说,时钟抖动就是时钟信号边沿的“颤抖”——信号本来应该在某个固定时间跳变,但实际时刻可能会前后波动。这种波动可能是随机的,也可能是确定性的。随机抖动(Random Jitter, Rj):符合高斯分布,像是你家猫咪不经意的晃动。确定性抖动(Deterministic Jitter, Dj):受限于特定周期或模式,像是邻居装修时的规律敲击声。⚠️ 注意,如果时钟抖动超出规格,DDR5可能无法正确接收或发送数据,内存错误、系统崩溃可就跟着来了!

weixin_43199439的博客 392

Java核心技术之类加载机制---类加载的时机

 我们已经知道,在Class文件中描述的各种信息,最终都需要加载到虚拟机中之后才能运行和使用。那么,虚拟机如何加载这些Class文件?  虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。  在Java语言里面,类型的加载、连接和初始化过程都是在程序运行期间完成的,这种策略虽然会令类加载时稍微增...

喜三仔的世界 414

uniapp - 强力解决 swiper 轮播图内嵌套视频导致滑动不流畅卡顿问题,轮播滑块视图容器里既有图片也有视频video组件共同存在出现滑动切换特别卡,轮播组件包裹视频播放器加载慢及层级过高解决

uni-app,h5移动端网页,微信小程序,支付宝小程序,Android安卓,苹果ios,app,nvue,swiper,轮播图,轮播图嵌套视频,卡顿,加载慢,左右滑动不流畅,很卡,滑动过快就会卡住,uniapp使用swiper组件里嵌套视频与图片如何解决卡顿问题,详细解决教程,swiper里有视频video,播放器,视频+图片轮播,层级过高及卡顿问题,没等看完视频就自动切换了,报错,无法加载播放,uniapp的App安卓苹果端,video老是加载,APP端video组件播放视频卡顿,抖音,快手,上下滑动视

🏆 前端领域优质创作者 1万+

面试笔记——java的类加载和对象创建小记

1 类加载器 1 java类加载器 java源代码.java文件通过编译成字节码.class文件后,需要被加载到java虚拟机的内存空间中使用,这个过程就是类加载。类加载依靠的是java类加载器 java类加载是java运行时环境的一部分,负责动态加载java类到java虚拟机的内存空间中,类通常是按需加载的,即第一次使用该类时才加载。由于有了类加载器,java运行时系统不需要知道文件的位置与文...

Routine_limon的博客 388

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

深入理解java虚拟机系列第三版读后小记:(十)jvm的类加载过程

深入理解java虚拟机系列第三版读后小记: 十 jvm的类加载过程前言类的生命周期类加载到jvm的主要阶段加载类的时机加载验证准备解析初始化总结 前言 上文介绍了class的结构和字节码指令集,本文将介绍jvm的类加载过程。 类的生命周期 一个类从被加载到jvm的内存知道被jvm卸载出内存为止,一共要经历加载,验证,准备,解析,初始化,使用,卸载七个阶段,这七个阶段完整的构成了一个类的生命周期,其中验证,准备,解析这三个阶段统称连接。 其中,加载,验证,准备,初始化,卸载的五个阶段顺序是确定的,解析有些场

264

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Java小记

一.JavaSE、Socket 1、实现事件监听的四种方式:    本类继承接口、外部类实现、内部类实现、内部匿名类实现。 2、socket的accept()方法会阻塞线程,注意该方法调用的位置和时机,防止程序阻塞遇到意想不到的效果 3、笔试小记:String aa=123  String aa=123.toString  String aa=(String)123都不对.String aa

sheen口开河 861

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

jni小记

读[深入理解Android卷一 全文-第二章]深入理解JNI小记 注册方式: 静态注册:依赖固定的命名规则(class_methodName),使用时才去寻找指针并保存 动态注册:依赖JNI数据结(JNINativeMethod保存java和native之间的关系 加载时机:System.loadLibarary(该函数多次重复加载相同的so库不会导致耗时正相关增加) 注册时机:System.lo...

柒月 164

【Java基础小记】0822

static 关键字在 Java 中用于定义静态成员。它有以下几个关键点:1、静态变量:属于类而不是实例,所有实例共享同一个静态变量。例如,public static int count 只会有一个 count 变量,所有对象都访问这个变量。2、静态方法:同样属于类而不是实例,可以直接通过类调用,而无需创建对象。例如,public static void printMessage() 可以用 ClassName.printMessage() 访问。

Coniary的博客 972

JAVA小记

标识符:用于Java程序中变量,类,方法等命名的符号 由字母,数字,下划线(——),美元($)组成,不能以数字开头 不能是Java关键字和保留字 严格区分大小写 标识符的命名最好能反应出其作用 JAVA语言中的字符char可以存储一个汉字吗? 可以。因为JAVA语言采用Unicode编码,Unicode编码占两个字节,中文也占两个字节。 重载:方法名相同,参数列表不同,与返回值类型无...

125

每周小记——JVM

本文剖析JVM核心机制:详述内存模型(堆、方法区、栈)及垃圾回收算法(标记-清除/复制/压缩)、分代策略与GC类型(Minor/Major/FullGC);解析类加载机制(双亲委派模型、加载/链接/初始化过程及三类加载器差异);阐述执行引擎(JIT编译、热点探测、逃逸分析);对比现代收集器(G1/ZGC/Shenandoah)及CMS优劣;探讨性能调优关键(吞吐量与延迟平衡、内存分配策略)。为Java性能优化提供理论支撑。

weixin_57655687的博客 1583

经典java题小记

java基础面试题

qq_37824570的博客 501

java反序列化小记

步骤作用序列化将转为字节数组,存入内存流反序列化从字节数组重建Person对象,不调用构造函数,但会自动回调(如果存在)安全意义如果中包含危险操作(如执行命令、触发反射链),攻击者可通过伪造字节流实现 RCE💡 这就是为什么“不要反序列化不可信数据”是 Java 安全的黄金法则!

2301_79783285的博客 735

static 使用小记

static实在类加载的时候进行初始化,写入内存中  程序中一般不用static 只是在特殊的时候才会用静态方法,静态(statice)方法不能调用非静态(non-static)方法 静态方法调用非静态方法是必须实例化静态对象 然后调用方法   例子main 就是静态方法 调非静态方法是就是实例化对象然后进行调用(new)       首先static的成员是在类加载的时候初始化的,JVM的CL

266

JVM学习小记

jvm学习小记

逆流的博客 328

java学习小记

  包含final方法的类是可以被继承的,但是定义为final的类不能被继承静态变量由上往下执行,静态类和静态方法在被用到时才加载 "不考虑上下文,以下创建了几个对象?并且指出输出结果String s1 = new String(""abc"");String s2 = new String(""abc"");   三个对象:“s1” “s2” “abc”if(s1== s2){    S...

weixin_34116110的博客 74

Java线程小记

前台线程(用户线程):业务主线程,JVM必须等待其执行完毕守护线程(后台线程):为前台线程服务,所有前台线程结束,守护线程直接终止GC垃圾回收线程,全程后台运行,程序退出则GC直接退出。定义全局布尔变量作为开关,外部修改开关,线程内部循环判断,安全退出。面试结论:线程终止只有两种方式:run() 方法正常执行完毕run() 内部抛出未捕获异常。

2401_87174643的博客 365
上一篇: 【小记】从公钥私钥理解HTTPS
下一篇: 【算法】不用乘、除、取余操作实现除法
皮皮蟹01
博客等级 码龄10年 29粉丝 76原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值