深入理解java虚拟机【Java虚拟机类生命周期】

Unity集成抖音小游戏:从IL2CPP配置到SDK接入全流程解析 本文详细解析了使用Unity开发抖音小游戏的完整流程。从关键的IL2CPP编译后端配置、PlayerSettings设置,到StarkSDK的接入与资源优化(如AutoStreaming),再到激励视频广告、录屏分享等核心功能的代码实现,提供了从环境准备到打包上传的全方位实战指南,帮助开发者高效完成技术适配。 阅读详情

C/C++等纯编译语言从源码到最终执行一般要经历:编译、连接和运行三个阶段,连接是在编译期间完成,而java在编译期间仅仅是将源码编译为Java虚拟机可以识别的字节码Class类文件,Java虚拟机对中Class类文件的加载、连接都在运行时执行,虽然类加载和连接会占用程序的执行时间增加性能开销,但是却可以为java语言带来高度灵活性和扩展性,java的针对接口编程和类加载器机制实现的OSGi以及热部署等就是利用了运行时类加载和连接的特性,java的Class类在虚拟机中的生命周期如下:
 

上图中加载、验证、准备、初始化和卸载这个五个阶段的顺序是确定的,而解析阶段则不一定,在某些情况下为了支持java语言的运行时动态绑定,也可以在初始化阶段之后再开始。

 

(1).加载:

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

在加载阶段,java虚拟机需要完成以下3件事:

a.通过一个类的全限定名来获取定义此类的二进制字节流。

b.将定义类的二进制字节流所代表的静态存储结构转换为方法区的运行时数据结构。

c.在java堆中生成一个代表该类的java.lang.Class对象,作为方法区数据的访问入口。

加载阶段与连接阶段是交叉进行的,加载阶段尚未完成,连接阶段可能已经开始,这些夹在加载阶段之中进行的动作仍然属于连接阶段,加载和连接阶段仍然保持着固定的先后顺序。

 

(2).验证:

验证是连接阶段的第一步,其目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机的安全,如果验证失败,会抛出java.lang.VerifyError异常。

验证阶段的主要工作有:

a.文件格式验证:验证Class文件魔数、主次版本、常量池、类文件本身等等。

b.元数据验证:主要是对字节码描述的信息进行语义分析,包括是否有父类、是否是抽象类、是否是接口、是否继承了不允许被继承的类(final类)、是否实现了父类或者接口的方法等等。

c.字节码验证:是整个验证过程中最复杂的,主要进行数据流和控制流分析,如保证跳转指令不会跳转到方法体之外的字节码指令、数据类型转换安全有效等。

d.符号引用验证:发生在虚拟机将符号引用转化为直接引用的时候(连接第三阶段-解析阶段进行符号引用转换为直接引用),符号引用验证的目的是确保解析动作能正常执行,如果无法通过符号引用验证,则会抛出java.lang.IncompatibleClassChangeError异常的子类异常,如java.lang.IllegalAccessError、java.lang.NoSuchFieldError、java.lang.NoSuchMethodError等。

验证阶段对于虚拟机来说非常重要,但是不是一个必需的阶段,如果所运行的代码已经反复被使用和验证过了,可以通过-Xverify:none参数关闭大部分的验证措施,以提高虚拟机时间时间。

 

(3).准备:

准备阶段是正式为类变量(静态变量,注意不是实例变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配。

对于普通非final的类变量,如public static int value = 123;在准备阶段过后的初始值是0(数据类型的零值),而不是123,而把123赋值给value是在初始化阶段才进行的动作。

对于final的类变量,即常量,如public staticfinal int value =123;在准备阶段过程的初始值直接就是123了,不需要准备为零值。

 

(4).解析:

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。

符号引用(SymbolicReference):以一组符号来描述所引用的目标,与虚拟机内存布局无关,引用的目标不一定已经被加载到虚拟机内存中。

直接引用(DirectReference):可以直接指向目标的指针、相对偏移量或者是一个能间接定位到目标的句柄。直接引用和虚拟机实现的内存布局相关,同一个符号引用在不同虚拟机上翻译处理的直接引用不一定相同,如果有了直接引用,则引用的目标对象必须已经被加载到虚拟机内存中。

解析的动作主要针对类或接口、字段、类方法、接口方法四类符号引用进行解析。

 

(5).初始化:

初始化是类使用前的最后一个阶段,在初始化阶段java虚拟机真正开始执行类中定义的java程序代码。

Java虚拟机规范严格规定了有且只有以下四种情况必须立即对类进行初始化:

a.遇到new、获取静态变量(final常量除外)、为静态变量赋值以及调用静态方法时,如果类没有进行过初始化,则需要先触发其初始化。

b.使用java.lang.reflect包的方法对类进行反射调用的时候(Class.forName(…)),如果类还没有初始化,需要先触发对其的初始化。

c.当初始化一个类的时候,如果发现其父类还没有初始化,则需要先触发对其父类的初始化。

d.当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的类),虚拟机会先初始化这个类。

上述四种情况称为对一个类的主动引用,除此之外的引用方式都不会触发初始化,称为被动引用。

 

初始化的过程其实就是一个执行类构造器<clint>方法的过程,类构造器执行的特点和注意事项:

1).类构造器<clint>方法是由编译器自动收集类中所有类变量(静态非final变量)赋值动作和静态初始化块(static{……})中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序决定。静态初始化块中只能访问到定义在它之前的类变量,定义在它之后的类变量,在前面的静态初始化中可以赋值,但是不能访问。

2).类构造器<clint>方法与实例构造器<init>方法不同,它不需要显式地调用父类构造器方法,虚拟机会保证在调用子类构造器方法之前,父类的构造器<clinit>方法已经执行完毕。

3).由于父类构造器<clint>方法先与子类构造器执行,因此父类中定义的静态初始化块要先于子类的类变量赋值操作。

4). 类构造器<clint>方法对于类和接口并不是必须的,如果一个类中没有静态初始化块,也没有类变量赋值操作,则编译器可以不为该类生成类构造器<clint>方法。

5).接口中不能使用静态初始化块,但可以有类变量赋值操作,因此接口与类一样都可以生成类构造器<clint>方法。

 

接口与类不同的是:

首先,执行接口的类构造器<clint>方法时不需要先执行父接口的类构造器<clint>方法,只有当父接口中定义的静态变量被使用时,父接口才会被初始化。

其次,接口的实现类在初始化时同样不会执行接口的类构造器<clint>方法。

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

初始化阶段,当执行完类构造器<clint>方法之后,才会执行实例构造器的<init>方法,实例构造方法同样是按照先父类,后子类,先成员变量,后实例构造方法的顺序执行。
(6).使用:

当初始化完成之后,java虚拟机就可以执行Class的业务逻辑指令,通过堆中java.lang.Class对象的入口地址,调用方法区的方法逻辑,最后将方法的运算结果通过方法返回地址存放到方法区或堆中。

(7).卸载:

当对象不再被使用时,java虚拟机的垃圾收集器将会回收堆中的对象,方法区中不再被使用的Class也要被卸载,否则方法区(Sun HotSpot永久代)会内存溢出。

Java虚拟机规定只有当加载该类型的类加载器实例为unreachable状态时,当前被加载的类型才被卸载.启动类加载器实例永远为reachable状态,由启动类加载器加载的类型可能永远不会被卸载,类型卸载仅仅是作为一种减少内存使用的性能优化措施存在的,具体和虚拟机实现有关,对开发者来说是透明的.

 

卸载自定义来加载器加载的类的可靠做法为:

a.每次创建特定类加载器的新实例来加载指定类型的不同版本,这种使用场景下,一般就要牺牲缓存特定类型的类加载器实例以带来性能优化的策略了.

b.对于指定类型已经被加载的版本, 会在适当时机达到unreachable状态,被unload并垃圾回收.每次使用完类加载器特定实例后(确定不需要再使用时), 将其显示赋为null, 这样可能会比较快的达到jvm 规范中所说的类加载器实例unreachable状态, 增大已经不再使用的类型版本被尽快卸载的机会.

 

彩蛋:

最后希望大家多多支持 一键三连+评论下 并献上我自己整理的“大厂真题+微服务+MySQL+分布式+SSM框架+Java+Redis+数据结构与算法+网络+Linux+Spring全家桶+JVM+高并发+各大学习思维脑图+面试集合”


【AI 编程工具】Codex配置部署指南 目录一、环境准备与基础安装1. 系统兼容性检查2. 前置依赖安装3. 安装方式选择二、API密钥配置与认证1. 获取API密钥2. 配置文件设置3. 临时配置方式三、沙盒环境配置与安全策略1. 沙盒模式选择2. 安全最佳实践四、高级功能配置1. 模型上下文协议(MCP)配置2. 模型版本切换3. 自定义网关配置五、常见问题排查1. 安装失败2. API调用失败3. 处理速度慢4. 配置文件不生效六、生产环境部署建议macOS/Linux:官方提供稳定支持,推荐使用原生环境Windows:官方标注为实验性支持 阅读详情

相关推荐

KV Cache 详解:新手也能理解的 LLM 推理加速技巧

(Autoregressive)生成的,即每次生成一个 token,然后将其作为输入继续生成下一个 token。:如果序列太长,超过了 KV Cache 的存储限制,就需要丢弃最早的 tokens(类似滑动窗口)。时,每次只会生成一个新 token,然后再把这个 token 作为输入继续生成下一个 token。,只缓存计算过的 K,VK, V,每次只计算新 token 的 K,VK, V,从而提升推理效率。:如果输入的 prompt 发生变化,之前的 KV Cache 不能复用,必须重新计算。

Harry的博客 7359

同一进程中运行多个java虚拟机导致错误_Java高级编程基础:如何理解进程、线程与并发编程的关系...

并发编程与线程我们知道随着计算机芯片技术的发展,由最初的单核CPU发展到现在的多核CPU是在集成技术发展到一定程度后,采取的另外一项提高处理能力的方案。由于多核CPU的出现,使得并行执行成为可能。即使对单个应用程序来说,由于编译器优化和多核处理器的性能优化也会早就很多并发执行的情况。如此依赖并发编程成为一种编程方案,它主要借助多线程设计方式来完成。我们常说的并发性是指程序同时执行多个计算的能力。它...

weixin_39579483的博客 982

XCP_Basic 移植步骤

XCP_Basic 移植步骤

ggzzc的博客 2316

java虚拟机完成的任务_深入java虚拟机——生命周期

java虚拟机的存在就是为了一个任务——执行java程序。程序开始是他运行,结束时他停止。对应的,需要指出,在一台机器上运行了三个程序的话,就会有三个运行中的虚拟机(曾经一度错误的理解过)。java虚拟机实例通过调用某个初始类的main()方法来运行一个Java程序。而这个main()方法必须是共有的(public)、静态的(static)、返回值为void,并且接受一个字符串数组作为参数。任何拥...

weixin_33484711的博客 272

VS2019 +osg3.6.5+ earth3.2+qt5.14.2+osgQt 编译教程

用vs新建工程,稍后会在写一篇博客上分享四、结语至此,所有的编译就均已完成。

king_ink的博客 1134

英飞凌ADS开发环境搭建全流程:从安装到第一个程序烧录

本文详细介绍了英飞凌ADS开发环境搭建的全流程,包括环境准备、ADS安装与配置、MemTools烧录技巧等关键步骤。针对嵌入式开发者,特别提供了从安装到第一个程序烧录的实战指南,涵盖常见问题解决方案和优化建议,帮助开发者快速上手英飞凌AURIX系列微控制器的开发工作。

qsc901234的博客 333

多个java虚拟机 错误_java虚拟机崩溃或报运行时错误--解决办法

如果在java环境下运行多线程程序时报如下错误:## A fatal error has been detected by the Java Runtime Environment:## EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000000f637323, pid=10960, tid=10428## JRE version: Jav...

weixin_39897887的博客 1671

PSIM+PIL+CCS三剑客:手把手教你搞定DSP28335的软硬件联合调试

本文详细介绍了如何利用PSIM、PIL与CCS三款工具,实现DSP28335的软硬件联合调试。通过搭建兼容环境、从PSIM仿真生成PIL代码,再到实战联合调试与问题诊断,手把手指导开发者构建从虚拟模型到实际硬件的完整验证闭环,有效提升电力电子与电机驱动等领域的开发效率与可靠性。

weixin_29183637的博客 186

深入浅出Java虚拟机,从来没有人能把Java 虚拟机讲解的这么透彻

Java 虚拟机提供了许多配置参数,用于满足不同应用场景下,对程序性能的需求。学习 Java 虚拟机,你可以针对自己的应用,最优化匹配运行参数。(你可以用下面这个例子看一下自己虚拟机的参数列表。)其次,Java 虚拟机本身是一种工程产品,在实现过程中自然存在不少局限性。学习 Java 虚拟机,可以更好地规避它在使用中的 Bug,也可以更快地识别出 Java 虚拟机中的错误,再次,Java 虚拟机拥有当前最前沿、最成熟的垃圾回收算法实现,以及即时编译器实现。

老男孩的架构路 1005

OpenCv —— 检测车牌号(附完整源码)

OpenCv —— 检测车牌号

5601

【YOLOv11多模态融合改进】| CVPR2025 LCA轻量交叉注意力 双向模态交叉引导 + 双支路噪点抑制,兼顾纹理与热目标特征融合

可见光模态富含纹理、色彩、边缘细节,但夜间/低照度场景信噪比极低,暗区噪声泛滥;红外模态依靠热辐射凸显弱小目标、暗区物体轮廓,但缺失真实色彩与精细纹理。简单拼接/逐加融合仅做浅层特征叠加,无法建立可见光纹理、红外热特征的双向引导关联,两类模态互补信息无法精准互通;普通自注意力仅单模态内部建模,跨模态交互匮乏,红外热目标易被可见光暗噪声淹没,可见光有效纹理易被红外灰度信息覆盖;

Limiiiing的博客 117

【虚拟机】深入理解java虚拟机【Java虚拟机类生命周期】

深入理解java虚拟机【Java虚拟机类生命周期】

xjavaxx的博客 725

AUTOSAR系统服务篇 - BswM的使用

本文档是对4.0.3版及更高版本的AUTOSAR模式管理应用的介绍。其主要目的是为AUTOSAR的用户和开发人员提供基于示例的AUTOSAR模式管理不同方面的详细概述,这些示例在文中进行了解释。本文中的代码清单共同构成了示例ECU的配置。第2章解释了基础的模式管理概念,例如一般的模式、如何实现模式切换、模式管理者和模式用户的角色等。其次介绍了应用模式管理和基础软件模式管理的依赖关系,两者密切相关。基础软件模式管理器是AUTOSAR R4.0中的中央模式管理模块。它具有很高的可配置性。

IOT2017的博客 846

《深入理解java虚拟机》学习笔记7——Java虚拟机类生命周期

C/C++等纯编译语言从源码到最终执行一般要经历:编译、连接和运行三个阶段,连接是在编译期间完成,而Java在编译期间仅仅是将源码编译为Java虚拟机可以识别的字节码Class类文件,Java虚拟机对中Class类文件的加载、连接都在运行时执行,虽然类加载和连接会占用程序的执行时间增加性能开销,但是却可以为java语言带来高度灵活性和扩展性,java的针对接口编程和类加载器机制实现的OSGi以及热

zhoutieVIP的博客 459

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

java 类卸载 static_《深入理解java虚拟机》学习笔记7——Java虚拟机类生命周期

C/C++等纯编译语言从源码到最终执行一般要经历:编译、连接和运行三个阶段,连接是在编译期间完成,而Java在编译期间仅仅是将源码编译为Java虚拟机可以识别的字节码Class类文件,Java虚拟机对中Class类文件的加载、连接都在运行时执行,虽然类加载和连接会占用程序的执行时间增加性能开销,但是却可以为java语言带来高度灵活性和扩展性,java的针对接口编程和类加载器机制实现的OSGi以及热...

weixin_32807903的博客 187

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

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

(转)《深入理解java虚拟机》学习笔记7——Java虚拟机类生命周期

C/C++等纯编译语言从源码到最终执行一般要经历:编译、连接和运行三个阶段,连接是在编译期间完成,而java在编译期间仅仅是将源码编译为Java虚拟机可以识别的字节码Class类文件,Java虚拟机对中Class类文件的加载、连接都在运行时执行,虽然类加载和连接会占用程序的执行时间增加性能开销,但是却可以为java语言带来高度灵活性和扩展性,java的针对接口编程和类加载器机制实现的OSGi以及热...

weixin_30371875的博客 66

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Java虚拟机详解

如果没有双亲委派,那么用户是不是可以自己定义一个java.lang.Object的同名类,java.lang.String的同名类,并把它放到ClassPath中,那么类之间的比较结果及类的唯一性将无法保证,因此,双亲委派模型可以防止内存中出现多份同样的字节码。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException),子加载器才会尝试自己去加载。启动类加载器,扩展类加载器,应用程序类加载器,自定义类加载器。5.对象头的Mark Word图。

2401_84177041的博客 524

精心整理的JVM笔记带你轻松学习Java虚拟机

最近看了深入理解Java虚拟机第三版,整理了一些基础结构图,算是比较全的了,做一下笔记,大家一起学习。

程序员高级码农的博客 965

Java春招面试复习:JVM系列基础图

前言 最近看了深入理解Java虚拟机第三版,整理了一些基础结构图,算是比较全的了,做一下笔记,大家一起学习。 1.Java虚拟机运行时数据区图 JVM内存结构是Java程序员必须掌握的基础。 程序计数器 程序计数器,可以看作当前线程所执行的字节码的行号指示器 它是线程私有的。 Java虚拟机栈 线程私有的,生命周期与线程相同。 每个方法被执行的时候都会创建一个"栈帧",用于存储局部变量表(包括参数)、操作数栈、动态链接、方法出口等信息。 局部变量表存放各种基本数据类型boolean、byte、cha

Viper的程序员修炼手册 429

系统流程图和程序流程图的区别_Java程序员必备掌握的一些Java基础流程图

引言最近看了深入理解Java虚拟机第三版,整理了一些基础结构图,算是比较全的了,做一下笔记,大家一起学习。1.Java虚拟机运行时数据区图JVM内存结构是Java程序员必须掌握的基础。程序计数器程序计数器,可以看作当前线程所执行的字节码的行号指示器它是线程私有的。Java虚拟机栈线程私有的,生命周期与线程相同。每个方法被执行的时候都会创建一个"栈帧",用于存储局部变量表(包括参数)、操作数栈、动态...

weixin_39860108的博客 170
上一篇: 5年大厂Java高频面试题及答案整理(二)
下一篇: 什么是MYSQL?
奇迹摘星w
博客等级 码龄6年 1844粉丝 189原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值