Java类加载的解析阶段实际上从哪里开始?
我刚刚读完Java虚拟机规范,这让我感到困惑。在阅读了规范之后,就我的总体理解而言,我认为类的整体实例化包括以下步骤,顺序如下:Java类加载的解析阶段实际上从哪里开始?,java,jvm,classloader,Java,Jvm,Classloader,我刚刚读完Java虚拟机规范,这让我感到困惑。在阅读了规范之后,就我的总体理解而言,我认为类的整体实例化包括以下步骤,顺序如下: 创建/加载:类加载器定位表示类的字节流,可以是文件或网络流,也可以是实现类加载器以获取的任何内容。如果找不到类,则抛出ClassNotFoundException。此时,已经发生了一些基本的验证,如果字节数组不表示Java类(例如,缺少幻数),则抛出ClassFormatError,如果运行的JVM实例不支持类版本,则抛出UnsupportedClassVersio
- 创建/加载:类加载器定位表示类的字节流,可以是文件或网络流,也可以是实现类加载器以获取的任何内容。如果找不到类,则抛出
。此时,已经发生了一些基本的验证,如果字节数组不表示Java类(例如,缺少幻数),则抛出ClassNotFoundException
,如果运行的JVM实例不支持类版本,则抛出ClassFormatError
UnsupportedClassVersionError
- 链接:该类连接到JVM中。如果出现问题,将抛出
的子类。链接由三个子步骤组成:LinkageError
- 验证:确保字节流表示一个Java类,例如,字节码没有形式错误,例如方法字节码的操作数堆栈溢出。如果类验证失败,将抛出
VerifyError
- 准备:JVM为所有静态字段分配内存,并可能创建一个实例模板以加速实例创建。创建虚拟方法表。此阶段不会引发类加载特定错误。(不过可能会抛出
)OutOfMemoryError
- 解析:现在以运行时常量池的形式加载到方法区域的所有符号引用都解析为此JVM加载的实际类型。如果可以解析符号引用但导致定义冲突,则会抛出
。如果找不到引用的类,将抛出一个不兼容ClassChangeError
,它基本上包装了一个NoClassDefFoundError
,该异常是由试图加载该引用类的类加载器抛出的。如果引用的类引用自身,则抛出ClassNotFoundException
。解决方案可以采用两种方式之一,这取决于JVM的实现者classcircularyError
- Eager:对其他字段、方法或类的所有符号引用现在都已解析
- Lazy:符号引用的解析将推迟到首次使用方法时进行。这可能会导致引用不存在的类的类在不需要解析该引用的情况下不会抛出错误
- 验证:确保字节流表示一个Java类,例如,字节码没有形式错误,例如方法字节码的操作数堆栈溢出。如果类验证失败,将抛出
静态
初始化器。如果异常是由此类初始值设定项引起的,则此异常将重新包装在异常InInitializeRerror
中我想知道的内容:今天JVM中的解决方案是否应该像我描述的那样理解?还是我错了,分辨率仍然可以被理解为固定时间线中的一个专用步骤,正如图片所示?很难说,但我认为您在文档中只发现了一点差异或歧义。文档中的步骤定义得不太准确,因此实现可能有点具体,步骤实际上可能有点重叠,等等。实现中的主要关注点可能是速度,而不是绝对的逻辑清晰性
试着研究一下OpenJDK的源代码,你可能会发现一些有趣的东西。你的图片显示,在准备工作之后,解析总是出现,但这不起作用。准备时需要直接超类,因为您需要了解超类的实例字段,以确定特定类的对象实例内存布局。此外,类的静态初始值设定项及其