jvm运行原理以及类加载器实例详解

 更新时间:2021年5月2日 15:01  点击:1417

JVM运行原理

首先从“.java”代码文件,编译成“.class”字节码文件,然后类加载器将“.class”字节码文件中的类给加载带JVM中,最后就是JVM执行写好的代码。执行过程如下图

类加载器

类加载过程

加载 -> 验证 -> 准备 -> 解析 -> 初始化 -> 使用 -> 卸载

加载

一旦JVM进程启动之后,一定会先把类加载到内存中,然后从main()方法的入口代码开始执行

public class HelloWorld {
    public static void main(String[] args) {
        
    }
}

加载指是将类CLass文件读入到内存中,并创建一个java.lang.Class对象

类的加载器由类加载器完成,类加载器通常由JVM提供,除此之外,可以通过继承ClassLoader基类来创建自己的类加载器

通过使用不同的类加载器,可以从不同来源加载类的二进制数据

  • 从本地文件系统加载class文件
  • 从JAR包加载class文件,JDBC编程时用到的数据库驱动类就放在JAR文件中,JVM可以从JAR文件中直接加载该class文件
  • 通过网络加载class文件
  • 把一个java源文件动态编译,并执行加载

准备阶段

验证

根据Java虚拟机规范,来校验加载进来的“.class”文件中的内容,是否符合指定的规范,如果“.class”文件被人篡改,里面的字节码不符合规范,那么JVM是没法执行这个字节码。所在把“.class”文件加载到内存后,必须先验证一下,检验他必须完全符合JVM规范,才交给JVM来运行。其主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证

  • 文件格式验证:主要验证字节流是否符合Class文件格式规范,并且能被当前的虚拟机加载处理。例如:主,次版本号是否在当前虚拟机处理的范围之内。常量池中是否有不被支持的常量类型。指向常量的中的索引值是否存在不存在的常量或不符合类型的常量
  • 元数据验证:对字节码描述的信息进行语义的分析,分析是否符合java的语言语法的规范
  • 字节码验证:最重要的验证环节,分析数据流和控制,确定语义是合法的,符合逻辑的。主要的针对元数据验证后对方法体的验证。保证类方法在运行时不会有危害出现
  • 符号引用验证:主要是针对符号引用转换为直接引用的时候,是会延伸到第三解析阶段,主要去确定访问类型等涉及到引用的情况,主要是要保证引用一定会被访问到,不会出现类等无法访问的问题

准备

给引用的类分配一定的内存空间,然后给里面的类变量(也就是static修饰的变量)分配内存空间,来一个默认的初始值

解析

实际上是把将类的二进制数据中的符号引用替换成直接引用的过程,这个部分的内容比较复杂,设计到JVM的底层

  • 符号引用:符号引用是以一组符号来描述所引用的目标,符号可以是任何的字面形式的字面量,只要不会出现冲突能够定位到就行。布局和内存无关
  • 直接引用:是指向目标的指针,偏移量或者能够直接定位的句柄。该引用是和内存中的布局有关的,并且一定加载进来的

解析主要包括:

  • 类或接口的解析
  • 字段解析
  • 类方法解析
  • 接口方法解析

初始化

初始化是为类的静态变量赋予正确的初始值,准备阶段和初始化阶段看似有点矛盾,其实是不矛盾的,如果类中有语句:private static int a = 10,它的执行过程是这样的,首先字节码文件被加载到内存后,先进行链接的验证这一步骤,验证通过后准备阶段,给a分配内存,因为变量a是static的,所以此时a等于int类型的默认初始值0,即a=0,然后到解析(后面在说),到初始化这一步骤时,才把a的真正的值10赋给a,此时a=10

一个非常重要的规则,就是如果初始化一个类的时候,发现他的父类还没初始化,那么必须先初始化他的父类

加载器

启动类/根类加载器

Bootstrap ClassLoader,他主要是负责加载我们在机器上安装的Java目录下的核心类的,是用原生代码来实现的,并不继承自 java.lang.ClassLoader(负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类)。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作

扩展类加载器

Extension ClassLoader,负责加载JRE的扩展目录,lib/ext或者由java.ext.dirs系统属性指定的目录中的JAR包的类。由Java语言实现,父类加载器为null

应用程序类加载器

Application ClassLoader,被称为应用(也称为系统)类加载器,它负责在JVM启动时加载来自Java命令的-classpath选项、java.class.path系统属性,或者CLASSPATH换将变量所指定的JAR包和类路径。程序可以通过ClassLoader的静态方法getSystemClassLoader()来获取系统类加载器。如果没有特别指定,则用户自定义的类加载器都以此类加载器作为父加载器。由Java语言实现,父类加载器为ExtClassLoader。

类加载器加载Class大致要经过如下8个步骤:

  1. 检测此Class是否载入过,即在缓冲区中是否有此Class,如果有直接进入第8步,否则进入第2步
  2. 如果没有父类加载器,则要么Parent是根类加载器,要么本身就是根类加载器,则跳到第4步,如果父类加载器存在,则进入第3步
  3. 请求使用父类加载器去载入目标类,如果载入成功则跳至第8步,否则接着执行第5步
  4. 请求使用根类加载器去载入目标类,如果载入成功则跳至第8步,否则跳至第7步
  5. 当前类加载器尝试寻找Class文件,如果找到则执行第6步,如果找不到则执行第7步
  6. 从文件中载入Class,成功后跳至第8步
  7. 抛出ClassNotFountException异常
  8. 返回对应的java.lang.Class对象

自定义类加载器

除了上面那几种之外,还可以自定义类加载器,去根据你自己的需求加载你的类

类加载机制

JVM的类加载机制主要有如下3种:

  • 全盘负责:所谓全盘负责,就是当一个类加载器负责加载某个Class时,该Class所依赖和引用其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入
  • 双亲委派:所谓的双亲委派,则是先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父加载器,依次递归,如果父加载器可以完成类加载任务,就成功返回;只有父加载器无法完成此加载任务时,才自己去加载
  • 缓存机制。缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中。这就是为很么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因

双亲委派机制

这就是所谓的**双亲委派模型:**先找父亲去加载,不行的话再由儿子来加载

  • 双亲委派机制,其工作原理的是,如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式,即每个儿子都很懒,每次有活就丢给父亲去干,直到父亲说这件事我也干不了时,儿子自己才想办法去完成
  • 双亲委派机制的优势:采用双亲委派模式的是好处是Java类随着它的类加载器一起具备了一种带有优先级的层次关系,通过这种层级关可以避免类的重复加载,当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次。其次是考虑到安全因素,java核心api中定义类型不会被随意替换,假设通过网络传递一个名为java.lang.Integer的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.Integer,而直接返回已加载过的Integer.class,这样便可以防止核心API库被随意篡改

总结

到此这篇关于jvm运行原理以及类加载器的文章就介绍到这了,更多相关jvm运行原理及类加载器内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

[!--infotagslink--]

相关文章

  • Powershell实现编写和运行脚本

    本文为那些对学习 Windows PowerShell 命令行和脚本编写环境感兴趣的系统管理员提供了资源。也请告诉我们本网站如何才能对您更有用处。...2020-06-30
  • C#隐式运行CMD命令(隐藏命令窗口)

    这篇文章主要介绍了C#隐式运行CMD命令(隐藏命令窗口),本文实现在winform窗口中运行CMD命令,需要的朋友可以参考下...2020-06-25
  • 解决Pycharm 运行后没有输出的问题

    这篇文章主要介绍了解决Pycharm 运行后没有输出的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-06
  • Python运行提示缺少模块问题解决方案

    这篇文章主要介绍了Python运行提示缺少模块问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-05-10
  • PHP的运行机制与原理(底层)

    说到php的运行机制还要先给大家介绍php的模块,PHP总共有三个模块:内核、Zend引擎、以及扩展层;PHP内核用来处理请求、文件流、错误处理等相关操作;Zend引擎(ZE)用以将源文件转换成机器语言,然后在虚拟机上运行它;扩展层是一组...2015-11-24
  • C#判断程序是否是管理员权限运行的方法代码示例

    这篇文章主要介绍了C#判断程序是否是管理员权限运行的方法代码示例,本文直接给出实现代码例子,需要的朋友可以参考下...2020-06-25
  • 在Linux上运行C#的方法

    这篇文章主要介绍了在Linux上运行C#的方法,实例分析了Linux平台下Mono软件包的应用技巧,以及在此基础之上的C#运行方法,具有一定的参考借鉴价值,需要的朋友可以参考下...2020-06-25
  • java中Base64编码原理实例讲解

    这篇文章主要介绍了java中Base64编码原理实例讲解,文章讲解的很清晰,有对于这方面不太懂的同学可以研究下...2021-02-10
  • python基于opencv检测程序运行效率

    这篇文章主要介绍了python基于opencv检测程序运行效率,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-05-09
  • Vue中key的作用及原理详解

    本文主要介绍了Vue3中key的作用和工作原理,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-10-13
  • hbuilder怎么运行php?如何用HBuilder调试PHP程序

    本文详细介绍了用HBuilder调试PHP程序的教程,对初学php的同学来说很有用,有兴趣的同学可以看看。 先到这里下载HBuilder(HBuilder是最棒的PHPIDE,可以参考PHP是世界上...2017-07-06
  • C# URL短地址压缩算法及短网址原理解析

    这篇文章主要介绍了C# URL短地址压缩算法及短网址原理解析,本文重点给出了算法代码,需要的朋友可以参考下...2020-06-25
  • 解析C/C++中如何终止线程的运行

    本篇文章是对C/C++中如何终止线程运行的方法进行了详细的分析介绍,需要的朋友参考下...2020-04-25
  • 在Visual Studio 中使用git及Git概念

    Git是一个开源的分布式版本控制系统,可以有效、高速的处理从很小到非常大的项目版本管理,是目前使用范围最广的版本管理工具,本文重点给大家介绍在Visual Studio 中使用git及git的工作原理,感兴趣的朋友一起看看吧...2021-05-19
  • Python基础之Socket通信原理

    这篇文章主要介绍了Python基础之Socket通信原理,文中有非常详细的代码示例,对正在学习python基础的小伙伴们有非常好的帮助,需要的朋友可以参考下...2021-04-22
  • .NET 5 部署在docker上运行的方法

    这篇文章主要介绍了.NET 5 部署在docker上运行的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-06
  • 浅谈Java自定义类加载器及JVM自带的类加载器之间的交互关系

    这篇文章主要介绍了浅谈Java自定义类加载器及JVM自带的类加载器之间的交互关系,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-22
  • VS2010写的程序在自己电脑可以运行、其他电脑上不能运行的解决方案

    自己用Visual Studio 2010 旗舰版写了一个软件,在自己电脑上运行完全没有问题,但是拷贝到其他人电脑上之后不管双击还是以管理身份运行,均没有反应,进程管理器中相关进程也只是一闪而过...2020-06-25
  • 如何将tomcat源码以maven方式运行

    这篇文章主要介绍了如何将tomcat源码以maven方式运行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
  • python Popen 获取输出,等待运行完成示例

    今天小编就为大家分享一篇python Popen 获取输出,等待运行完成示例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-05-06