【JavaEE】JVM的组成及类加载过程

  • 博主简介:想进大厂的打工人
  • 博主主页:@xyk:
  • 所属专栏: JavaEE初阶 

本文我们主要讲解一下面试中常见的问题,如果想深入了解,请看一下《Java虚拟机规范》这本书


目录

文章目录

一、JVM简介

二、JVM整体组成

2.1 运行时数据区组成

2.2 小结

三、JVM类加载

3.1 类加载过程

四、类加载什么时候会触发

五、双亲委派模型


一、JVM简介

JVM 是 Java Virtual Machine 的简称,意为 Java虚拟机。

虚拟机是指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统,JVM是通过软件模拟Java字节码的指令集,JVM中只是主要保留了PC寄存器,其他的寄存器都进行了裁剪。

二、JVM整体组成

JVM整体组成可分为四个部分:

1.类加载器(ClassLoader)

2.运行时数据区(Runtime Data Area)

3.执行引擎(Execution Engine)

4.本地库接口(Native Interface)

各个组成部分的用途:

程序在执行之前先要把java代码转换成字节码(.class文件),JVM首先需要把字节码通过一定的方式 类加载器(ClassLoader) 把文件加载到内存中 运行时数据区(Runtime Data Area) ,而字节码文件是JVM的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器 执行引擎(Execution Engine) 将字节码翻译成底层系统指令再交由CPU去执行,而这个过程中需要调用其他语言的接口 本地库接口(Native Interface) 来实现整个程序的功能,这就是这4个主要组成部分的职责与功能。

2.1 运行时数据区组成

jvm的运行时数据区,不同虚拟机实现可能略微有所不同,但都会遵从Java虚拟机规范,Java 8 虚拟机规范规定,Java虚拟机所管理的内存将会包括以下几个运行时数据区域:

1.程序计数器(Program Counter Register)

程序计数器是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器,记录当前线程执行到哪个指令。

特征:线程私有,由于JVM的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,也就是一个处理器都只会执行一条线程中的指令。因此为了线程切换后能恢复到正确的执行位置,每个线程都由独立的程序计数器。

如果线程正在执行Java中的方法,程序计数器记录的就是正在执行虚拟机字节码指令的地址,如果是Native方法,这个计数器就为空(undefined),因此该内存区域是唯一一个在Java虚拟机规范中没有规定OutOfMemoryError的区域。

2.Java虚拟机栈(JVM Stacks)

Java虚拟机栈(Java Virtual Machine Stacks)描述的是Java方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法返回地址等信息每个方法从调用直至执行完成的过程,都对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

特性:线程私有(不绝对,局部变量可以互相访问),它的生命周期和线程相同。

3.本地方法栈

本地方法栈(Native Method Stack)与虚拟机栈的作用是一样的,只不过虚拟机栈是服务Java方法的,而本地方法栈是为虚拟机调用Native方法服务的。

4.堆区(Heap)

Java堆(Java Heap)是Java虚拟机中内存最大的一块,是被所有线程共享的。我们常见的 JVM 参数设置 -Xms10m 最小启动内存是针对堆的,-Xmx10m 最大运行内存也是针对堆的

堆的作用:程序中创建的所有对象(new对象,类的成员变量)都在保存在堆中。

 关于新生代和老生代,后面再讲~

5.方法区(元数据区)

方法区(Methed Area)用于存储已被虚拟机加载的类信息(类对象)、常量、静态变量、即时编译后的代码等数据。

在《Java虚拟机规范中》把此区域称之为“方法区”,而在 HotSpot 虚拟机的实现中,在 JDK 7 时此区域叫做永久代(PermGen),JDK 8 中叫做元空间(Metaspace)。

PS:永久代(PermGen)和元空间(Metaspace)是 HotSpot 中对《Java虚拟机规范》中方法区的实现,它们三者之间的关系就好比,对于一辆汽车来说它定义了一个部分叫做“动能提供装置”,但对于不同的汽车有不同的实现技术,比如对于燃油车来说,它的“动能提供装置”的实现技术就是汽油发动机(简称发动机),而对于电动汽车来说,它的“动能提供装置”的实现就是电动发动机(简称电机),发动机和电机就相当于永久代和元空间一样,它是对于“制动器”也就是方法区定义的实现。

运行时常量池是方法区的一部分,存放字面量与符号引用:

  1. 字面量 : 字符串(JDK 8 移动到堆中) 、final常量、基本数据类型的值。
  2. 符号引用 : 类和结构的完全限定名、字段的名称和描述符、方法的名称和描述符。

2.2 小结

记住这几个原则:

  1. 局部变量在栈上
  2. 普通成员变量在堆上
  3. 静态成员变量,基本数据类型的值,final常量,在方法区/元数据区上

三、JVM类加载

3.1 类加载过程

对于一个类来说,它的生命周期是这样的:

主要分为这几个步骤:

1. 加载:找到.class文件,并且读文件内容到内存中
2. 连接:
        2.1. 验证:检查.class文件格式是否正确
        2.2. 准备:给类对象分配内存空间,内存空间中的数据全是0
        2.3. 解析:初始化字符串常量,将符号引用转为直接引用

那么符号引用是什么?

符号引用以一组符号来描述所引用的目标。符号引用可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可,符号引用和虚拟机的布局无关。

3. 初始化:针对类对象进行初始化(调用构造方法,初始化静态成员,执行静态代码块,类要是有父类还需要加载父类)

四、类加载什么时候会触发

不是JVM一启动,就把所有的.class都加载了,整体是一个“懒加载“的策略,非必要,不加载~~

什么是叫做必要?

1.创建了这个类的实例

2.使用了这个类的静态方法/静态属性

3.使用子类,会触发父类的加载

一旦加载过后,后续不再重复加载~

五、双亲委派模型

双亲委派模型:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最 终都应该传送到最顶层的启动类加载器中,只有当父加载器反馈自己无 法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载。

JVM中,加载类,需要用到一组特殊的模块,类加载器~

在JVM中,内置了三个 类加载器:

  1. BootStrap ClassLoader(java规范的标准库)
  2. Extension ClassLoader(JVM扩展库)
  3. Application ClassLoader(加载用户提供的第三方库/项目中的类)

加载一个类的时候,先从Applicaton ClassLoader开始加载,但是先把任务交给父亲Extension ClassLoader,Extension ClassLoader收到请求再交给自己的父亲BootStrap ClassLoader,由于BootStrap ClassLoader没有了父亲,此时就自己来搜索自己负责的区域,如果搜索到,直接进行后续加载步骤,如果没搜到,再交给自己孩子去处理,依此类推到Application ClassLoader,当都没有找到的时候,会抛出一个 ClassNotFound Exception.

为了避免bug,保证BootStrap ClassLoader先加载,Application ClassLoader后加载~

双亲委派模型优点:

1. 避免重复加载类:比如 A 类和 B 类都有一个父类 C 类,那么当 A 启动时就会将 C 类加载起来,那么在 B 类进行加载时就不需要在重复加载 C 类了。
2. 安全性:使用双亲委派模型也可以保证了 Java 的核心 API 不被篡改,如果没有使用双亲委派模
型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 java.lang.Object
类的话,那么程序运行的时候,系统就会出现多个不同的 Object 类,而有些 Object 类又是用户
自己提供的因此安全性就不能得到保证了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/18147.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ELK日志记录——Kibana组件——grok 正则捕获插件

grok 正则捕获插件 grok 使用文本片段切分的方式来切分日志事件 内置正则表达式调用 %{SYNTAX:SEMANTIC} ●SYNTAX代表匹配值的类型,例如,0.11可以NUMBER类型所匹配,10.222.22.25可以使用IP匹配。 ●SEMANTIC表示存储该值的一个变量声明&…

生产环境 kafka 平滑迁移之旅

文章目录 背景分析测试环境验证现实很残酷两种抉择-----leader分区切换方案选择实施步骤手工副本集增加步骤手工leader分区切换步骤 总结 背景 线上kafka集群,3台机器,3个broker;其中某台机器因为硬件故障,需要停机维修&#xff…

表的增删改查

1、创建表 mysql> create table employee ( -> id int(1) comment 员工编号, -> name varchar(6) comment 员工名字, -> gender varchar(2) comment 员工性别, -> salary int (4) comment 员工薪资); Query OK, 0 rows affected (0.01 sec) 2、…

解析三防平板在工业自动化的应用价值

三防平板作为一种具有出色性能和特殊设计的电子设备,为工业自动化领域带来了巨大的应用价值。采用英特尔凌动四核处理器,三防平板具备先进的技术与处理能力。同时配备Window 10操作系统,这款三防平板能够轻松执行多种任务指令。此外&#xff…

支持向量机推导之r||w||=1的限制转化

支持向量机推导之r||w||1的限制转化 很多同学肯定是学过支持向量机的,也可能大致的理解了支持向量机这个算法,我想大部分人在学习这个算法的时候,对于推导过程有一步应该是不太理解。 我先简要介绍一下SVM,SVM的核心思想在于找到一个多维空间…

基于深度学习的高精度深海鱼检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要:基于深度学习的高精度深海鱼检测识别系统可用于检测与定位深海鱼目标,利用深度学习算法可实现图片、视频、摄像头等方式的深海鱼目标检测识别,另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测模型训练数据集&a…

python接口自动化(十七)--Json 数据处理---一次爬坑记(详解)

简介 有些 post 的请求参数是 json 格式的,这个前面发送post 请求里面提到过,需要导入 json模块处理。现在企业公司一般常见的接口因为json数据容易处理,所以绝大多数返回数据也是 json 格式的,我们在做判断时候,往往只…

小白到运维工程师自学之路 第四十六集 (mongodb复制集)

一、概述 1、 MongoDB复制集(MongoDB Replica Set)是MongoDB提供的一种高可用性和数据冗余的解决方案。它由多个MongoDB实例组成,其中一个作为主节点(Primary),其他节点则扮演从节点(Secondary&…

小程序开发及生态丰富,还需要App吗?

微信小程序自2017年推出以来,其生态系统得到了迅速的发展和壮大。作为中国最大的社交平台之一,微信拥有庞大的用户基础。微信小程序作为微信生态系统的一部分,自然而然地吸引了大量用户。据对公开资料进行统计,2021年全网小程序数…

UE5《Electric Dreams》项目PCG技术解析 之 PCGCustomNodes详解(三)SG_CopyPointsWithHierarchy

继续解析《Electric Dreams》项目中的自定义节点和子图:SG_CopyPointsWithHierarchy和PostCopyPoints-OffsetIndices 文章目录 前导文章标准组合拳SG_CopyPointsWithHierarchyPostCopyPoints-OffsetIndices使用情景Execute with ContextIteration Loop Body 小结 前…

超有趣的linux命令2

超有趣的linux命令2 此次实验命令均在Ubuntu16.04版本上测试 注意有些命令需要在图形化界面才能显示效果 温馨提示:可能有人是第一次接触Ubuntu,所以下面详细写了如何配置源和网络,以及安装命令的方式 1. 首先配置软件源 以命令行方式配置…

mybatis学习记录

63、数据访问-整合mybatis-配置版_哔哩哔哩_bilibili id和mapper接口里方法名称对应,返回类型就写对应的返回类型地址 两个文件的名称要一样 注解配置就是直接在mapper里写sql语句,不用写xml文件了,这种方式使用的相对少一点。