深入探索JVM类加载机制 — 类加载的过程之准备、解析

本文详细介绍了JVM类加载机制中的准备和解析阶段。准备阶段为类变量分配内存并设置初始值,通常为零值,除非存在ConstantValue属性。解析阶段则将常量池中的符号引用替换为直接引用,这一过程可能在类加载时或使用前进行,对字段和方法的访问权限也会在此阶段检查。解析动作主要针对7类符号引用进行,对应常量池的8种类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

准备

准备阶段是正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置类变量初 始值的阶段,从概念上讲,这些变量所使用的内存都应当在方法区中进行分配,但必须注意到方法区 本身是一个逻辑上的区域,在JDK 8及之后,类变量则会随着Class对象一起存放在Java堆中,这时候“类变量在 方法区”就完全是一种对逻辑概念的表述了。

这时候进行内存分配的 仅包括类变量,而不包括实例变量,实例变量将会在对象实例化时随着对象一起分配在Java堆中。其 次是这里所说的初始值“通常情况”下是数据类型的零值。

 

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

Java中所有基本数据类型的零值:

在“通常情况”下初始值是零值,那言外之意是相对的会有某些“特殊情况”:如果类字段 的字段属性表中存在ConstantValue属性,那在准备阶段变量值就会被初始化为ConstantValue属性所指定 的初始值,假设上面类变量value的定义修改为:

 

编译时Javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据Con-stantValue的设置 将value赋值为123。

解析

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

解析阶段中所说的直接 引用与符号引用的关联:

·符号引用(Symbolic References):符号引用以一组符号来描述所引用的目标,符号可以是任何 形式的字面量,只要使用时能无歧义地定位到目标即可。符号引用与虚拟机实现的内存布局无关,引 用的目标并不一定是已经加载到虚拟机内存当中的内容。各

·直接引用(Direct References):直接引用是可以直接指向目标的指针、相对偏移量或者是一个能 间接定位到目标的句柄。直接引用是和虚拟机实现的内存布局直接相关的,同一个符号引用在不同虚 拟机实例上翻译出来的直接引用一般不会相同。如果有了直接引用,那引用的目标必定已经在虚拟机 的内存中存在。

《Java虚拟机规范》之中并未规定解析阶段发生的具体时间,只要求了在执行ane-warray、 checkcast、getfield、getstatic、instanceof、invokedynamic、invokeinterface、invoke-special、 invokestatic、invokevirtual、ldc、ldc_w、ldc2_w、multianewarray、new、putfield和putstatic这17个用于 操作符号引用的字节码指令之前,先对它们所使用的符号引用进行解析。

虚拟机实现可以根据需要来⾃⾏判断,到底是在类被加载器加载时就对常量池中的符号引

⽤进⾏解析,还是等到⼀个符号引⽤将要被使⽤前才去解析它。类似地,对⽅法或者字段

的访问,也会在解析阶段中对它们的可访问性(public、protected、private 、< package

> ) 进⾏检查。

对同⼀个符号引⽤进⾏多次解析请求是很常⻅的事情,除invokedynamic指令以外,

拟机实现可以对第⼀次解析的结果进⾏缓存,譬如在运⾏时直接引⽤常量池中的记录,并

把常量标识为已解析状态,从⽽避免解析动作重复进⾏。⽆论是否真正执⾏了多次解析动

作,Java虚拟机都需要保证的是 同⼀个实体中,如果⼀个符号引⽤之前已经被成功解析

过,那么后续的引⽤解析请求就应当⼀直能够成功;同样地,如果第⼀次解析失败了,其

他指令对这个符号的解析请求也应该收到相同的异常,哪怕这个请求的符号在后来已成功

加载进Java虚拟机内存之中。

不过对于invokedynamic指令,上面的规则就不成立了。当碰到某个前面已经由invokedynamic指令 触发过解析的符号引用时,并不意味着这个解析结果对于其他invokedynamic指令也同样生效。因为 invokedynamic指令的目的本来就是用于动态语言支持,它对应的引用称为“动态调用点限定符 (Dynamically-Computed Call Site Specifier)”,这里“动态”的含义是指必须等到程序实际运行到这条指 令时,解析动作才能进行。相对地,其余可触发解析的指令都是“静态”的,可以在刚刚完成加载阶 段,还没有开始执行代码时就提前进行解析。

解析动作主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符这7 类符号引用进行,分别对应于常量池的CONSTANT_Class_info、CON-STANT_Fieldref_info、 CONSTANT_Methodref_info、CONSTANT_InterfaceMethodref_info、 CONSTANT_MethodType_info、CONSTANT_MethodHandle_info、CONSTANT_Dyna-mic_info和 CONSTANT_InvokeDynamic_info 8种常量类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值