[JVM]JVM内存模型,类加载过程,双亲委派模型

news2024/9/27 10:42:49

文章目录

    • 1. JDK,JRE,JVM分别是什么,它们之间有什么联系?
    • 2. JVM内存区域划分
    • 3. JVM类加载过程
    • 4. 一个经典面试题
    • 5. JVM 双亲委派模型

1. JDK,JRE,JVM分别是什么,它们之间有什么联系?

JDK: 是Java开发工具包,包含了编写,编译,调试和运行Java程序所需要的所有工具和组件。比如编译器Javac,JavaAPI,调试工具等,JDK是针对Java开发人员的,它包含了Jre,还有编译器和其他工具,可以用来编写和调试Java程序

JRE: 是Java运行时环境,包括了Java虚拟机和Java标准类库,用于在计算机中运行Java程序。

JVM: 是Java虚拟机,是Java程序的运行环境,负责将Java代码转化成为可以在计算机上运行的机器码,并且提供必要的条件支持。

2. JVM内存区域划分

JVM内存区域包括:程序计数器,栈区,堆区,方法区。

程序计数器: 内存中最小的区域,保存了下一条要执行的指令地址在哪。这里的指令就是使用JVM加载后的字节码文件,程序要想执行,那么此时就要使用JVM把字节码文件加载起来,放到内存中国,程序就会一条一条的把指令从内从中取出来,放到CPU上执行,那么此时就需要随时记住,当前执行到哪一条了。

我们知道CPU是并发执行程序的,CPU不是只给你一个进程提供服务的,要伺候所有的进程。因为操作系统是以线程为单位进行跳读执行的。每个线程都记录自己的执行位置。

还有就是我们的程序计数器,是在线程中存在的,并且每个线程只有一个程序计数器。

栈区: 用来存储局部变量和方法调用的信息。方法调用的时候,每次调用一个新的方法,就会设计到一个入栈操作,每次执行完一个方法之后,都涉及到出栈操作。

看如下代码:

void A(){
    B();
}
void B(){
    C();
}
void C(){

}

在这里插入图片描述

如果不停的在栈区中存放方法的信息,那么就会造成栈溢出。那么此时就要联想到我们的递归方法,自己调用自己,那一个方法的信息不停的添加到栈区中,如果我们此时的递归条件,没有写正确,那么就会造成栈溢出。

在JVM中,栈的空间是比较小的,并且在JVM中可以配置栈空间的大小,但是一般也就是几M,或者几十M。这里的栈区其实就和我们在学习数据结构时学的基本一样。

我们要注意的是,这个栈区是在每个线程中存储一份的。

堆区: 一个进程只有一份,那么就是进程中的多个线程,共享我们这里的堆区 这个也是北村中空间占有最大的区域,我们一般写代码时,new出来的对象,都添加到对中,对象的成员变量自然也是在堆中了。

但是这里有这一句话,大家看对不对,内置类型的变量,在栈区上。引用类型的变量在堆区上。其实这个说法是错误的,正确的应该是局部变量,在栈区,成员变量和new出来的对象,在堆上

void func(){
    String s = new String()l
}

此时这个操作在执行的时候,s和new String()是两个东西。
在这里插入图片描述

因为String 是引用类型,那么此时这里的s是一个引用类型的变量,但是它在一个方法中,方法一执行结束,那么此时这个s就从栈区消失了,那么此时的这个s就是一个局部变量。

这里的new String() 是一个对象的实体,是在堆上储存的

class Test{
    String s = new String();
}
new Test();

这里的s是一个引用类型的变量,并且此时s是在Test类中的一个成员变量,那么此时的这个s就就是在堆区中的。

同样我们的new String() 这个对象主体,也是在堆区中的。
在这里插入图片描述

方法区: 方法区中,存放的是"类对象"

.class文件会被加载到内存中,也就被JVM构造成类对象(加载的称为"类加载")

这里的类加载,就是放到方法区中,那么类对象就是描述这个类长啥样。好比说,类的名字是什么,里面有哪些成员,有哪些方法,每个成员叫啥名字,是啥类型,public/private,每个方法叫啥名字,是啥类型,public。private,方法里面包含的指令。这里我们有没有想到Java的反射机制呢???😏😏😏

类对象中还有一个很重要的东西,就是静态成员。静态成员是使用static关键字修饰的成员,也称为类属性,而我们的普通成员,叫做实例属性

3. JVM类加载过程

类加载:其实就是设计一个运行是环境的一个重要的核心的功能。类加载就是把.class文件,加载到内存中,构建成类对象

类加载大致分为三个大步骤:
在这里插入图片描述

Loading环节:

先找到对应的.class文件,然后打开并读取.class文件,同时初步的生成一个类对象

在Loading的一个关键环节,.class文件到底是啥样的呢?
在这里插入图片描述

.class文件的格式正如上图,其中 u4 就是4个字节的unsigned int u2 就是2个字节的unsigned int ,cp_info/field_info 都是结构体。field_info表示的是类中的信息,method_info就表示的是方法中的信息

我们可以观察这个.class文件的格式,既可以看到 .class文件就把.java文件中的核心信息都表述进去了,只不过组织格式发生了变化。

Linking:

连接一般就是创建好几个实体之间的联系。

Verification: 表示的是校验过程,主要就是验证读到的内容是不是和规范中规定的格式,完全匹配。如果发现这里读到的数据格式不符合规范,就会类加载失败,并且抛出异常。

PreParation: 准备阶段是这个是为类中定义的变量,静态变量,被static修饰的变量,分配内存并设置变量初始化的阶段。

给静态变量分配内存,并且设置0值

Resoulation:表示的是解析。.class文件中,常量是集中放置的,每个常量有一个编号。.class文件的结构体里初始化情况下只是记录了编号。就需要根据编号找到对应的内容,填充到类对象中。

Initializing: 真正对类对象进行初始化,尤其是针对静态成员。

4. 一个经典面试题

大家看看下面的代码片段,判断输入结构是什么?

class A{
    public A(){
        System.out.println("执行A类中无参的构造方法");
    }
    {
        System.out.println("执行A类中的构造方法块");
    }
    static{
        System.out.println("执行A类中的静态代码块");
    }
}
class B extends A{
    public B(){
        System.out.println("执行B类中无参的构造方法");
    }
    {
        System.out.println("执行B类中的构造方法块");
    }
    static{
        System.out.println("执行B类中的静态代码块");
    }
}
public class TestDemo2 extends B {
    public static void main(String[] args) {
        new TestDemo();
        new TestDemo();
    }
}

这里有一个大的原则:

  1. 类加载阶段会进行 静态代码块的执行,要想创建实例,那么势必要先进行类加载
  2. 这里的静态代码块只是在类加载阶段执行一次
  3. 构造方法和构造代码块,每次实例化都会被执行,构造代码块在构造方法的前面执行。
  4. 父类执行在前,子类执行在后。
  5. 我们这里的main方法开始执行,然后调用TestDemo2的方法,因此要执行main方法,就需要先加载TestDemo2
  6. TestDemo2类继承自B,要加载TestDemo2,就要先加载B
  7. B继承自A,要加载B,就要先加载A

所以最后的执行结果就是:

执行A类中的静态代码块
执行B类中的静态代码块
执行A类中的构造方法块
执行A类中无参的构造方法
执行B类中的构造方法块
执行B类中无参的构造方法
执行A类中的构造方法块
执行A类中无参的构造方法
执行B类中的构造方法块
执行B类中无参的构造方法

5. JVM 双亲委派模型

其实这个JVM中的双亲委派模型在面试中是非常喜欢考的,但是这个东西是不重要的,这个东西其实也不是很难理解的,这个东西在我们日常编码的时候没有指导意义。即使它有一个高大上的名字。

其实这里的双亲委派模型就是一个类加载环节

这个环节是处于Loading状态的

双亲委派模型,描述的就是JVM中的一个类加载器,如何根据类的权限名,就如(java.lang.String)找到.class文件的过程。

这个类加载器是JVM中提供了一个专门的对象,叫做类加载器,负责进行类加载,当然找文件的过程也是有类加载器来负责的。

这里的.class文件,可能放置的位置有很多,有的放到JDK目录中,有的放到项目目录中,还有在其他的特定位置。

默认的类的加载器,主要有3个

  1. BootStrapClassLoader:负责加载标准库中的类(String,ArrayList,random,Scanner等)
  2. ExtensionClassLoader: 负责加载JDK扩展的类
  3. ApplicationClassLoader:负责加载当前项目中的类

其实我们程序员也可以自定义类加载器,来加载其他目录中的类,就比如Tomcat就自定义了类加载器,用来专门加载webapps里面的.class文件

我们的双亲委派模型,就描述这个找目录的过程,也就是上述类加载器是如何配合的

考虑加载我们的java.util.String

  1. 程序启动,先进入ApplicationclassLoader类加载器
  2. ApplicationClassLoader就会检查下它的父加载器是否已经加载过了,如果没有,就调用父加载器extensionClassLoader
  3. ExtensionclassLoader也会检查下,它的父加载器是否加载过了,如果没有,就调用父加载器BootStrapClassloader
  4. BootStropClassLoader也会检查下,它的父加载器是否加载过了,但是自己没有父加载器,于是就扫描自己负责的目录
  5. java.lang.String这个类在标准库中内找到,直接由BootStrapClassLoader负责后序的加载过程,查询环节就结束了。
    在这里插入图片描述

类加载器,加载我们自己写的Test类

首先前面还是一样的

  1. 程序启动,先进入ApplicationclassLoader类加载器
  2. ApplicationClassLoader就会检查下它的父加载器是否已经加载过了,如果没有,就调用父加载器extensionClassLoader
  3. ExtensionclassLoader也会检查下,它的父加载器是否加载过了,如果没有,就调用父加载器BootStrapClassloader也会检查下,它的父加载器是否加载过了,但是自己没有父加载器,于是就扫描自己负责的目录
  4. BootStropClassLoader也会检查下,它的父加载器是否加载过了,但是自己没有父加载器,于是就扫描自己负责的目录。但是还是没有找到,那么此时就回到子记载器中继续扫描。
  5. ExtensionClassLOader也扫描自己负责的目录,也没扫描到,回到子加载器继续扫描
  6. ApplicationClassLoader也扫描自己负责的目录,能找到Test类,于是进行后溪的加载,查找目录环节结束。
    在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

9、面向对象、泛型与反射

目录一、构造函数二、继承与重写三、泛型四、反射1 - 反射的基本概念2 - 反射的基础数据类型3 - 反射APIa - 获取Type类型b - 获取struct成员变量的信息c - 获取struct成员方法的信息d - 获取函数的信息e - 判断类型是否实现了某接口五、reflect.Valuea - 空value判断b - 获取V…

分布式算法 - Paxos算法

Paxos算法是Lamport宗师提出的一种基于消息传递的分布式一致性算法,使其获得2013年图灵奖。自Paxos问世以来就持续垄断了分布式一致性算法,Paxos这个名词几乎等同于分布式一致性, 很多分布式一致性算法都由Paxos演变而来。Paxos算法简介Paxos算法是Lampo…

【RabbitMQ笔记05】消息队列RabbitMQ七种模式之Routing路由键模式

这篇文章,主要介绍消息队列RabbitMQ七种模式之Routing路由键模式。 目录 一、消息队列 1.1、Routing模式 1.2、案例代码 (1)引入依赖 (2)编写生产者 (3)编写消费者 一、消息队列 1.1、Ro…

我为什么选择Linux mint 21.1 “Vera“ ? Mint安装优化调教指南(分辨率DPI)

前言:为什么是Mint 笔者算是Linux老用户了,作为一个后端开发,尝试了多种不同发行版。 一开始是Manjaro这种Arch系,但是其对于开发而言实在是太过不稳定;每次滚动更新都要解决很多冲突。不适合当生产力(本…

Python实现贝叶斯优化器(Bayes_opt)优化支持向量机分类模型(SVC算法)项目实战

说明:这是一个机器学习实战项目(附带数据代码文档视频讲解),如需数据代码文档视频讲解可以直接到文章最后获取。1.项目背景贝叶斯优化器(BayesianOptimization) 是一种黑盒子优化器,用来寻找最优参数。贝叶斯优化器是基…

动态规划-规划兼职工作

动态规划-规划兼职工作 一、问题描述 你打算利用空闲时间来做兼职工作赚些零花钱。这里有 n 份兼职工作,每份工作预计从 startTime 开始到 endTime 结束,报酬为 profit。给你一份兼职工作表,包含开始时间 startTime,结束时间 en…

Netty入门学习笔记1-定义

1、定义 Netty 是一个异步的、基于事件驱动的网络应用框架,用于快速开发可维护、高性能的网络服务器和客户端。 官网:Netty: Home 2、地位 Netty 在 Java 网络应用框架中的地位就好比:Spring 框架在 JavaEE 开发中的地位 以下的框架都使…

在Kotlin中探索 Activity Results API 极简的解决方案

Activity Results APIActivity Result API提供了用于注册结果、启动结果以及在系统分派结果后对其进行处理的组件。—Google官方文档https://developer.android.google.cn/training/basics/intents/result?hlzh-cn一句话解释:官方Jetpack组件用于代替startActivity…

【Vue学习】Vue高级特性

1. 自定义v-model Vue中的自定义v-model指的是在自定义组件中使用v-model语法糖来实现双向绑定。在Vue中,通过v-model指令可以将表单元素的值与组件实例的数据进行双向绑定。但是对于自定义组件,如果要实现v-model的双向绑定,就需要自定义v-…

Kotlin 高端玩法之DSL

如何在 kotlin 优雅的封装匿名内部类(DSL、高阶函数)匿名内部类在 Java 中是经常用到的一个特性,例如在 Android 开发中的各种 Listener,使用时也很简单,比如://lambda button.setOnClickListener(v -> …

每日资源分享(彩虹外链PHP网盘V5.4更新 新增用户系统与分块上传)

demo软件园每日更新资源 1.跟我一起写Python 完整版PDF Python 就为我们提供了非常完善的基础代码库,覆盖了网络、文件、GUI、数据库、文本等大量内容。用 Python 开发,许多功能不必从零编写,直接使用现成的即可。 《跟我一起写 Python》是笔…

C++设计模式(20)——迭代器模式

亦称: Iterator 意图 迭代器模式是一种行为设计模式, 让你能在不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素。 问题 集合是编程中最常使用的数据类型之一。 尽管如此, 集合只是一组对…

【数据库】 SQLServer

SQL Server 安装 配置 修改SQL Server默认的数据库文件保存路径_ 认识 master :是SQL Server中最重要的系统数据 库,存储SQL Server中的元数据。 Model:模板数据库,在创建新的数据库时,SQL Server 将会复制此数据…

FreeRTOS的Delay函数

两个Delay函数有两个延时函数vTaskDelay:至少等待指定个数的Tick Interrupt才能变为就绪态xTaskDelayUtil:等待到指定的绝对时刻,才能变为就绪态个人感觉这两个延时函数就是,比如一个我等3个小时,一个是我等到下午3点的…

HTML5 Drag and Drop

这是2个组合事件 dom对象分源对象和目标对象 绑定的事件也是分别区分源对象和目标对象 事件绑定 事件顺序 被拖拽元素,事件触发顺序是 dragstart->drag->dragend; 对于目标元素,事件触发的顺序是 dragenter->dragover->drop/…

Python|每日一练|链表|双指针|数组|递归|图算法|单选记录:删除链表的倒数第 N 个结点|下一个排列|迷宫问题

1、删除链表的倒数第 N 个结点(链表,双指针) 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 进阶:你能尝试使用一趟扫描实现吗? 示例 1: 输入:head …

ccc-pytorch-感知机算法(3)

文章目录单一输出感知机多输出感知机MLP反向传播单一输出感知机 内容解释: w001w^1_{00}w001​:输入标号1连接标号0(第一层)x00x_0^0x00​:第0层的标号为0的值O11O_1^1O11​:第一层的标号为0的输出值t:真实…

【Linux】孤儿进程 | 环境变量 | 命令行参数 | 进程优先级

文章目录1. 孤儿进程2. 环境变量1. PATH环境变量证明ls是系统指令修改自己写的可执行程序对应路径2. env——查看系统环境变量3. 获取环境变量envpenvirongetenv 函数获取 (主流)4. 总结3 . 命令行参数理解命令行参数4. 进程优先级优先级与权限的区分为什么会有优先级&#xff…

Android 动态切换应用图标方案

经常听到大家讨论类似的需求,怀疑大厂是不是用了此方案,据我个人了解,多数头部 app 其实都是发版来更新节假日的 icon。当然本方案也是一种可选的方案,以前我也调研过,存在问题和作者所述差不多,此外原文链…

使用Pyparsing为嵌入式开发定义自己的脚本语言

Python在嵌入式开发中也很流行生成实用脚本。Pyparsing还允许你轻松地定义在Python上下文中运行的定制脚本语言。Python实现的系统旨在能够独立执行用户传递的一系列命令。你希望系统以脚本的形式接收命令。用户应该能够定义条件。这种对通信中逻辑元素的最初简单的声音要求&am…