JVM类加载机制

这篇具有很好参考价值的文章主要介绍了JVM类加载机制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

JVM类加载机制,jvm,jvm

自己编写的Java代码,是如何在各种各样的操作系统上运行起来的?

Java文件通过javac编译成class文件,这种中间码被称为字节码,然后由jvm加载字节码,运行时解释器将字节码解释为一行行机器码来执行,在程序运行期间,即时编译器能会针对热点代码将该部分字节码编译成机器码以获得更高的执行效率。在整个运行时,解释器和即时编译器相互配合使Java程序几乎能够达到和编译型语言一样的执行速度。

jvm加载字节码的过程称为类加载,类加载流程的目的:把一份被javac编译过的class文本文件,通过加载,生成某种形式的Class数据结构进入内存,程序可以调用这个数据结构来构造出object这个过程是在运行时进行的,这也是Java动态拓展性的根基

JVM类加载机制,jvm,jvm

  1. 这张图表现了一个类的生命周期,完整一点的话,我们可以在最开始加上javac编译阶段。而“类加载"只包括加载、连接、初始化这三个过程。
  2. 需要区分“类加载”与“加载”,加载只是类加载的第一个环节。
  3. 解析部分是灵活的,它可以在初始化环节之后再进行,实现所谓的“后期绑定”这点后面在讲到解析环节时会详细讲。其他环节的顺序不可改变。

加载

“加载”(Loading)阶段是整个“类加载”(Class Loading)过程中的一个阶段,在加载阶段,Java虚拟机需要完成以下三件事情:

  • 1)通过一个类的全限定名来获取定义此类的二进制字节流。
  • 2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
  • 3)在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。

加载是一个读取Class文件,将其转化为某种静态数据结构存储在方法区内,并在堆中生成一个便于用户调用的java.lang.Class类型的对象的过程。

JVM类加载机制,jvm,jvm

《Java虚拟机规范》对这三点要求其实并不是特别具体,留给虚拟机实现与Java应用的灵活度都是相当大的。例如“通过一个类的全限定名来获取定义此类的二进制字节流”这条规则,它并没有指明二进制字节流必须得从某个Class文件中获取,确切地说是根本没有指明要从哪里获取、如何获取。仅仅这一点空隙,Java虚拟机的使用者们就可以在加载阶段搭构建出一个相当开放广阔的舞台,例如:

  • 从ZIP压缩包中读取,这很常见,最终成为日后JAR、EAR、WAR格式的基础。
  • 从网络中获取,这种场景最典型的应用就是Web Applet。
  • 运行时计算生成,这种场景使用得最多的就是动态代理技术,在java.lang.reflect.Proxy中,就是用了ProxyGenerator.generateProxyClass()来为特定接口生成形式为“*$Proxy”的代理类的二进制字节流。
  • 由其他文件生成,典型场景是JSP应用,由JSP文件生成对应的Class文件。
  • 从数据库中读取,这种场景相对少见些,例如有些中间件服务器(如SAP Netweaver)可以选择
  • 把程序安装到数据库中来完成程序代码在集群间的分发。
  • 可以从加密文件中获取,这是典型的防Class文件被反编译的保护措施,通过加载时解密Class文件来保障程序运行逻辑不被窥探。
  • ……

相对于类加载过程的其他阶段,非数组类型的加载阶段(准确地说,是加载阶段中获取类的二进
制字节流的动作)是开发人员可控性最强的阶段。加载阶段既可以使用Java虚拟机里内置的引导类加载器来完成,也可以由用户自定义的类加载器去完成,开发人员通过定义自己的类加载器去控制字节流的获取方式(重写一个类加载器的findClass()或loadClass()方法),实现根据自己的想法来赋予应用程序获取运行代码的动态性。

连接:验证

JVM类加载机制,jvm,jvm

对文件格式的验证发生在加载阶段,如果通过才能顺利加载,顺利加载后,此时方法区内虽然已经存在了该class的静态结构,堆中也存在了该class类型的对象但是这并不代表着JVM已经完全认可了这个类,如果程序想要使用这个类那么就必须进行连接,而连接的第1步就是进一步对这个类进行验证。我们来看看到底对方法区内的class静态结构进行了哪些方面的验证?

第一点是元数据验证,第二点是字节码验证。简单概括来说就是对class静态结构进行语法和语义上的分析保证其不会产生危害虚拟机的行为。如果这两个步骤验证通过,那么虚拟机会姑且认为该class是安全的,但是这并不意味着验证已经完全结束了还有一道对符号引用进行验证的步骤,是在解析阶段内发生的。而解析阶段我们之前也提到过,它可以在初始化阶段之前或者之后进行。符号引用验证可以看作是对类自身以外(常量池中的各种符号引用)的各类信息进行匹配性校验,通俗来说就是,该类是否缺少或者被禁止访问它依赖的某些外部类、方法、字段等资源。符号引用验证的主要目的是确保解析行为能正常执行,如果无法通过符号引用验证,Java虚拟机将会抛出一个java.lang.IncompatibleClassChangeError的子类异常。

连接:准备

 JVM类加载机制,jvm,jvm

为该类型中定义的静态变量赋零值

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

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

JVM类加载机制,jvm,jvm

如果类字段的字段属性表中存在ConstantValue属性,那在准备阶段变量值就会被初始化为ConstantValue属性所指定的初始值,类变量value的定义为:public static final int value = 123;编译时Javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据Con-stantValue的设置将value赋值为123。

连接:解析

JVM类加载机制,jvm,jvm

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

那什么是符号引用和直接引用呢?

当一个Java类被编译成class文件之后,比如一个类A,它引用了B这个类,在编译阶段,A这个类是不知道B有没有被编译的,而且此时B也一定没有被加载,所以A不知道B的实际地址,这个时候在A的class文件中将会用一个字符串来代表B的地址。这个字符串就被称为符号引用。在运行的时候,如果触发了A的类加载,到解析阶段发现B没有加载,这个时候,会触发B的类加载,此时A中的字符串会被B的实际地址所代替,这就叫直接引用

解析又分为静态解析和动态解析,因为Java有多态机制,如果上面提到的B是一个实体类,那么这样的解析称为静态解析,如果B是一个接口或者是抽象类的时候,这个时候就没有办法确定这个引用的实际地址,既然没有那就先留着。等到运行阶段发生了调用,这个时候虚拟机中的调用栈将会得到具体的类型信息,这个时候再进行解析就可以得到明确的直接引用。这个过程就叫做动态解析。这也是为什么解析阶段会发生在初始化阶段之后,实现后期绑定。

当解析步骤完成意味着整个连接部分的完成,这也就是说外部加载的Java类,已经成功的引入到了你的程序中。

初始化

初始化阶段就很简单了,先判断代码中是否存在主动资源初始化操作,如果有的话,那么执行主动资源初始化动作是指class层面的一些静态代码块,成员变量的赋值操作。 肯定是不包括构造函数的,构造函数是对象层面的,这个class是类层面的。只有显示的调用new指令才会调用构造函数进行对象的实例化,这是对象层面。

回顾

JVM类加载机制,jvm,jvm

从JVM的角度来看,加载阶段的读取二进制流这个动作,以及初始化阶段这两个部分开放了主导权给用户用户可以自由控制,而剩下的所有部分都是由虚拟机全权包揽,由其内部来完成。文章来源地址https://www.toymoban.com/news/detail-686978.html

到了这里,关于JVM类加载机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JVM类加载机制

    自己编写的Java代码,是如何在各种各样的操作系统上运行起来的? Java文件通过javac编译成class文件,这种中间码被称为字节码,然后由jvm加载字节码,运行时解释器将字节码解释为一行行机器码来执行,在程序运行期间,即时编译器能会针对热点代码将该部分字节码编译成机

    2024年02月10日
    浏览(27)
  • JVM类加载机制(六)

    类加载器(ClassLoader)是 Java 虚拟机(JVM)的重要组成部分,负责将类的字节码加载到内存中并转换为可执行的 Java 类。类加载器的主要任务是根据类的名称查找字节码文件并加载到内存中,然后进行验证、准备和解析等操作,最终生成可执行的类。 类加载器的分类: 启动类

    2024年02月06日
    浏览(37)
  • JVM的类加载机制

    1、概述: JVM是Java语言实现跨平台的关键 ,Java语言的运行过程:         *.java通过编译器编译为*.class,通用字节码文件并不能直接被操作系统所识别,针对不同的操作系统可安装对应的JVM,JVM将字节码解释为当前平台所能识别的机器码实现“跨平台”。 JVM执行class文件

    2024年02月07日
    浏览(29)
  • JVM:类加载机制

    Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被称作虚拟机的类加载机制。 一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历 加载、验证

    2024年01月17日
    浏览(76)
  • 说一下JVM类加载机制?

    Java中的所有类,都需要由类加载器装载到JVM中才能运行。类加载器本身也是一个类,而它的工作就是把class文件从硬盘读取到内存中。 在写程序的时候,我们几乎不需要关心类的加载,因为这些都是隐式装载的,除非我们有特殊的用法,像是反射,就需要显式的加载所需要的

    2024年02月21日
    浏览(30)
  • JVM:Java类加载机制

            加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,类型的加载过程必须按照这种顺序按部就班地开始,而解析阶段则不一定:它在某些情况下可以在初始化阶段之后再开始, 这是为了支持Java语言的运行时绑定特性(也称为动态绑定或晚期绑定)。

    2024年01月21日
    浏览(29)
  • JVM类加载和双亲委派机制

    当我们用java命令运行某个类的main函数启动程序时,首先需要通过类加载器把类加载到JVM,本文主要说明类加载机制和其具体实现双亲委派模式。 类加载过程 : 类加载的过程是将类的字节码加载到内存中的过程,主要包括:加载--链接--初始化,其中链接还包括验证、准备、

    2024年02月09日
    浏览(32)
  • JVM:双亲委派机制&类加载器

    Java运行时环境有一个 java.lang 包,里面有一个 ClassLoader 类 我们自定义一个 String 类在 java.lang 包下,下面的main方法报错。原因是: 根据双亲委派机制,会向上找先是找到了 应用程序加载器(appClassLoader) ,然后向上找 扩展类加载器(ExtClassLoader) ,最后找 根类加载器(Boot Strap

    2024年02月01日
    浏览(27)
  • 【Java高级应用:深入探索Java编程的强大功能,JVM 类加载机制, JVM 内存模型,垃圾回收机制,JVM 字节码执行,异常处理机制】

    本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题 中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:

    2024年01月16日
    浏览(76)
  • 【Jvm】Java类加载机制是什么?

    什么是类的加载? 类的生命周期? 类加载器是什么? 双亲委派机制是什么? JVM将class文件字节码文件加载到内存中, 并将这些静态数据转换成方法区中的运行时数据结构,在堆(并不一定在堆中,HotSpot在方法区中)中生成一个代表这个类的java.lang.Class 对象,作为方法区类数

    2024年02月11日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包