【JVM】关于JVM的内部原理你到底了解多少(八股文面经知识点)

news2025/4/25 21:58:38

前言

🌟🌟本期讲解关于HTTPS的重要的加密原理~~~

🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客

🔥 你的点赞就是小编不断更新的最大动力                                       

🎆那么废话不多说直接开整吧~~

 

目录

​编辑

📚️1.认识JVM

📚️2.JVM的内部解析

2.1JVM的内存区域划分

 1.堆区(只有一份)

 2.栈区(可以有N份)

3.程序计数器

4.元数据区

2.2JVM类加载机制

1.加载

2.验证

3.准备

 4.解析

5.初始化

2.3垃圾回收机制(GC)

1.GC的前言

2.回收的内存

3.识别垃圾

引用计数

可达性分析

4. 内存空间的释放

标记清除

复制算法

标记整理

分代回收

📚️3.总结


 

📚️1.认识JVM

在开始认识JVM的时候,这个本就不是我们工作中所运用得到的,那么我们在开始学习JAVA的时候,我们就听说过JVM,即如下三个:

jdk:Java开发工具包

jre:Java运行时环境

jvm:Java虚拟机

并且还了解过:编译型语言和解释型语言,而这里我们所学习的Java就是一个“半编译型”与“半解释型”的语言;

所以我们这里Java这样实现的目的就是为了跨平台,例如:C++编会编译成二进制的机器指令,而不同的CPU的机器指令是不一样的

具体的实现过程:

首先通过java.c将代码.java文件转化为.class字节码文件,然后再具体的系统平台上执行的时候,通过jvm将上述的字节码文件转化为CPU能够识别的机器语言

总结:所谓的jvm就是在Java编程中实现跨平台,充当中间人翻译官的角色

📚️2.JVM的内部解析

2.1JVM的内存区域划分

这里的jvm其实也是一个进程,那么我们之前在学习了解的计算机的工作原理:【后端开发】JavaEE初阶——计算机是如何工作的???-CSDN博客

了解到进程是需要操作系统分配内存空间的,这里支持了Java程序的执行,我们在Java程序中变量分配到的内存资源,其实就是jvm从操作系统内分配到的内存资源;而不同功能会对应分割不同的区域,这就是“内存的区域划分

这里的内存内部如下:

 1.堆区(只有一份)

即在代码中new出来的对象都是存储在这个区域里,对象中持有的非静态成员变量也是在这个堆里;

堆⾥⾯分为两个区域:新⽣代和⽼⽣代,新⽣代放新建的对象,当经过⼀定 GC 次数之后还存活的对象 会放⼊⽼⽣代。新⽣代还有 3 个区域:⼀个 Endn + 两个 Survivor(S0/S1),后面会将

 2.栈区(可以有N份)

本地方法栈/虚拟机栈,描述了方法的调用的关系,和局部变量

补充:

动态链接:指向运⾏时常量池的⽅法引⽤。
⽅法返回地址:PC 寄存器的地址
3.程序计数器

占有比较小的空间,专门又来存储下一条要执行的java程序指令的地址

4.元数据区

元数据区是一个计算机常见的概念,这里主要指定就是辅助性质的,描述性质的属性;

例如:在硬盘上,不仅仅要存储文件的数据信息,还有其他的辅助属性:“文件的大小,文件的存储位置,文件的拥有者,文件的访问权限”统称为元数据

那么此时就有如下的面试题:

class Test{
    private int n;
    private static int m;
 
}

public static void mian(String[] arg){
    Test t=new Test();
}

此时分析:n,t,m在内存区域的哪里???

n:由于n是一个成员变量,那么此时就是在堆上面的

t:是一个引用类型的局部变量,那么此时就是在栈上面

m:由于m是static修饰的变量,叫类对象,那么此时就是在元数据区里

被static修饰的变量叫类属性,修饰的方法叫类方法

非static修饰的变量叫实例属性,非修饰的方法叫实例方法 

所谓的类对象:就是Test.class,在.class文件加载到内存上面的时候,就会将信息用对象来表示,这个对象就是 类对象,包含了很多的属性

2.2JVM类加载机制

类加载:所谓的加载其实指定就是Java进程运行吧.class文件从硬盘读取到内存并进行一系列的校验解析的过程;

这里的加载的步骤主要分为5步

1.加载

 把硬盘上的.class文件找到,打开文件读取里面的内容(是一个二进制的数据)

重点(双亲委派模型)

所谓的双亲委派模型就是描述了如何查找.class文件的策略;

jvm在进行类加载的操作中,有个专门的模块称之为“类加载器”,这里的的类加载器默认是3个;

BootstrapClassLoader(负责查找目标库的目录)

ExtensionClassLoader(负责查找扩展库的目录)

ApplicationClassLoader(负责查找当前项目的代码目录,以及第三方库的目录)

注意:上述的三个类加载器的关系是父子关系,但是这里的父子关系指的就是二叉树的指针关系

具体的工作的流程:

ApplicationClassLoader入口进入,但是自己不会搜索自己负责的目录,而是会发给ExtensionClassLoader,同上也不会搜索,继续给父亲BootstrapClassLoader,然后由于没有父亲,那么就会开始目标库目录,如果找到了就直接进入打开文件,若没有找到,那么给ExtensionClassLoader开始搜索扩展库目录,同上找到了打开文件,没有继续给儿子;

最后没有找到会继续在孩子这一辈的类加载器搜索,但是默认 ApplicationClassLoader是没有孩子的,那么就会类加载失败,抛出ClassNotFountExecption

具体的模型如下:

优点: 

可以有效的避免自己写的类不小心和标准库的名字重复后,导致标准库的类功能失效

2.验证

当前需要知道保证读到的文件的内容是合法的.class文件内容

具体的验证的依据,在Java虚拟机规范中有明确的格式的说明:

解释:

u4:四字节无符号整数

u2:两个字节无符号整数

magic:魔幻数字,表示当前二进制的文件的格式是那种类型

field_info:另一个结构体

3.准备

 给类对象申请内存的空间,此时申请到的内存空间,里面默认值就全部是0(这个阶段的类对象中的静态成员变量的值就相当于是0)

 4.解析

主要针对的就是类中的字符串常量进行处理

例如:

class Test{
  private String s="Hello";
}

 那么此时的.class文件就会包含这个hello,那么此时的存储的情况就是如下的:

解释:

我们可以知道这里的s变量存储了hello的字符串常量的地址,那么在文件中不存在地址这个概念的,那么这里的红线就是偏移量来代替了地址; 

后面.class文件加载到内存中的时候,就可以直接替换成真实的“hello”的地址了;

5.初始化

就是针对这个类对象完成后续的初始化;还要执行静态代码块的逻辑,或者触发父类的加载

2.3垃圾回收机制(GC)

1.GC的前言

在C语言中,动态管理内存,那么就是molloc申请内存,free释放内存,那么此时申请的内存是跟随整个进程的,这一点对于服务器是非常不友好的,如果申请了内存不释放就会导致内存泄漏的问题,但是free需要手动调用,就会又不确定的因素

所以在java中就引入了自动释放内存的机制就是:GC

但是这里的C语言C++追求的是极致性能,所以就没有引入,因为垃圾回收有一个重要的问题

(stop the world)STW问题

当触发垃圾回收机制的时候,很有可能当前程序的其他的业务逻辑就会暂停;但是现在的STW的时间控制在1ms以内了,也是可以接受的

2.回收的内存

说到垃圾回收机制,我们知道在内存中的区域进行了分区的,那么垃圾回收,回收的是哪一部分的“垃圾”呢?

程序计数器:不需要GC

栈:不需要GC,局部变量在代码执行结束之后会自动的销毁,与垃圾回收没有关系

元数据区:不需要GC,这里只涉及类加载,很少涉及类卸载

堆:这里就是GC的主要战场

在垃圾回收中,跟准确的说法就是“回收对象” 

在堆中,内存的回收具体是如下所示的:

解释:

中间的那块,代表就是一半不回收,一半回收,一般就是不进行回收,叫做“骑强派” 这里包含的空闲的内存就不用管了

3.识别垃圾

所谓的垃圾识别就是判断出当前这个对象是否还继续进行使用,如果没有继续进行使用,那么这个对象就可以进行回收了;

具体举例:

void func{
   Test t=new Test();

   t.func1;
}

那么此时的情况就是如下的:

解释:

那么我们可以知道,局部变量的生命的周期是很短的,那么接下来在执行到“}”的时候,这里就被释放了,没有指向这个地址,那么这个堆里的对象就是垃圾了;

那么此时涉及下面的代码,那么就比较复杂了:

Test t1=new Test();
Test t2=t1;
Test t3=t2;

 那么就引入了一个新的概念,来解决这个问题复杂的情况;

引用计数

这种方法在JVM中并没有进行使用,那么此时主要是用在其他的主流的语言上面的(Python,PHP)

具体方法:

就是给对象安排一个额外的空间,来保存当前这个对象有几个引用

具体实例如下:

Test a=new Test();
Test b=a;
a=null;
b=null;

对应的图示:

解释:

此时我们可以看到,两个引用指向这个对象,那么申请空间的保存的就是2,两个引用,如果栈的局部变量被释放后,或者为“null”那么这个里面的引用就是0,此时就可以进行释放了;

缺点:

问题1:消耗额外的内存空间:如果对每个对象安排一个计数器,如果程序中的对象太多了,那么此时就会造成额外的空间消耗

问题2:引用计数器可能会导致“循环引用的问题”,应用计数就无法进行正常的工作了;

 什么是循环引用,具体代码如下:

class Test{
  Test t;
}

Test a=new Test();
Test B=new Test();

a.t=b;
b.t=a;
a=null;
b=mull;

那么具体的图示就是如下所示的:

解释:

那么此时就会发现,由于a.t=b,这个操作,导致在堆里的new的对象中多出来了一个地址的指向,那么此时就会发现,计数器中的值就是2,如果a,b都为null了,那么就会出现计数器为1,但是没有任何指向对象的引用; 

我们可以知道此时就相当于是死锁的情况了,两个对象不能调用,但是这两个对象却不是垃圾;那么此时就引入了另一个垃圾识别的分析

可达性分析

这里的可达性其实就类似于二叉树的遍历,若其中一个点被断了,那么后面的子结点就是不可达的,那么此时后面的就是垃圾,因该被回收了;

具体的情况图示如下:

解释:

如果此时的结点就都是可达的,若其中b=null,那么包括b和它的子结点都是不可达的,那么就是垃圾,就应该被回收了; 

4. 内存空间的释放

在上述的垃圾的识别标记后,那么此时就应该执行内存空间的释放的操作了,具体的内存释放的操作即如下三种的操作的方式

标记清除

做法:将标记的垃圾直接进行清除(直接释放掉)

具体的图示如下:

那么此时的黑色部分就是垃圾被清除的部分内存;

问题:

此时就造成了内存的碎片问题,因为在申请内存空间的时候是申请的一段连续的内存空间,此时就会造成内存总空间够,但是申请不了,因为内存不是连续的是断层的 

复制算法

做法:将不是垃圾的内存对象复制到另一半内存中,然后将复制前的内存空间连垃圾一起释放掉

那么此时的图示就是如下的:

解释:

那么此时就是将不是垃圾的内存对象复制到另一边,然后将左边区域直接全部释放掉,此时就直接规避了内存的碎片化的问题

 缺点:

缺点显而易见,就是总共可用的内存直接性的下降了,并且复制的对象很多的时候,复制的开销也会变大

标记整理

做法:类似与顺序表中的删除中间元素的操作(搬运),就是将非垃圾的内存对象把垃圾给覆盖掉

具体的实例如下:

解释:

此时就将非垃圾的内存对象给往前面进行搬运,这样就会解决内存碎片化问题,以及内存总空间减少的问题,但是会涉及到内存搬运的开销 

分代回收

做法:就是依据不同类的对象,采取不同的方式

此时就是jvm中有专门负责周期性的扫描,一个对象被扫描一次可达性满足,那么就会年龄+1;jvm机会根据年龄的差异把堆内存的空间分为两个部分,“新生代/老年代” 

具体的图示如下:

解释:

 new出来的新的对象就存储在伊甸区,经过扫描后,大部分的对象都直接GG,然后幸存下来的就在生存区,再次进行伊甸区和生存区的扫描,若在伊甸区就和上面一样,若是生存区,那么就拷贝到另一个区域,反复如此(每次扫描年龄+1)若若干轮的GC任然存在,那么就认为这个对象的生存的周期比较长,那么就会拷贝在老年区域了;(此时的扫描的频率就会下降)若老年区的对象变成垃圾了,那就会通过标记整理的方式进行释放内存;

ok以上就是垃圾回收的具体方法步骤,当然这里还涉及到“垃圾收集器”,小伙伴们可以去了解一下CMS,G1,ZGC这三个

📚️3.总结

💬💬本期小编主要总结了JVM面经的常考题,主要讲解了JVM的内部实现原理包括内存区域的划分,类加载机制,垃圾的回收机制(GC)从什么是垃圾,如何进行识别,到最后的内存对象的释放,都做了比较详细的介绍~~~

🌅🌅🌅~~~~最后希望与诸君共勉,共同进步!!!


💪💪💪以上就是本期内容了, 感兴趣的话,就关注小编吧。

                 😊😊  期待你的关注~~~

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

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

相关文章

机器学习 ---模型评估、选择与验证(1)

目录 前言 一、为什么要有训练集与测试集 1、为什么要有训练集与测试集 2、如何划分训练集与测试集 二、欠拟合与过拟合 1、什么是欠拟合与欠拟合的原因 2、什么是过拟合与过拟合的原因 一些解决模型过拟合和欠拟合问题的常见方法: 解决过拟合问题&#…

第74期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区,集成了生成预训练Transformer(GPT)、人工智能生成内容(AIGC)以及大语言模型(LLM)等安全领域应用的知识。在这里,您可以找…

SpringBoot(八)使用AES库对字符串进行加密解密

博客的文章详情页面传递参数是使用AES加密过得,如下图所示: 这个AES加密是通用的加密方式,使用同一套算法,前端和后端都可以对加密之后的字符串进行加密解密操作。 目前线上正在使用的是前端javascript进行加密操作,将加密之后的字符串再传递到后端,PHP再进行解密操作。…

JavaScript逆向爬虫教程-------基础篇之JavaScript密码学以及CryptoJS各种常用算法的实现

目录 一、密码学介绍 1.1 为什么要学密码学?1.2 密码学里面学哪一些 二、字符编码三、位运算四、Hex 编码与 Base64 编码 4.1 Hex 编码4.2 Base64 编码 五、消息摘要算法 5.1 简介5.2 JS中的MD5、SHA、HMAC、SM3 六、对称加密算法 6.1 介绍6.2 加密模式和填充方式6.3 CryptoJ…

《实时流计算系统设计与实现》-Part 2-笔记

做不到实时 做不到实时的原因 实时计算很难。通过增量计算的方式来间接获得问题的(伪)实时结果,即使这些结果带有迟滞性和近似性,但只要能够带来尽可能最新的信息,那也是有价值的。 原因可分成3个方面: …

gdb调试redis。sudo

1.先启动redis-server和一个redis-cli。 2.ps -aux|grep reids查看redis相关进程。 3.开始以管理员模式附加进程调试sudo gdb -p 2968.注意这里不能不加sudo,因为Redis 可能以 root 用户启动,普通用户无法附加到该进程。否则就会出现可能下列情形&#…

长连接配置以及断线重连

目录 长连接index 主要进行连接 import SockJS from "sockjs-client"; import Stomp from "stompjs"; import { notification } from "antd"; // 网络请求API import { nowApiAddressObj } from "../api/nowApiAddressObj";// 工具 i…

LeetCode【0054】螺旋矩阵

本文目录 1 中文题目2 求解方法:数学模拟2.1 方法思路2.2 Python代码2.3 复杂度分析 3 题目总结 1 中文题目 给定一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 示例: 提示: 1 ≤ m …

万字长文解读深度学习——训练(DeepSpeed、Accelerate)、优化(蒸馏、剪枝、量化)、部署细节

🌺历史文章列表🌺 深度学习——优化算法、激活函数、归一化、正则化深度学习——权重初始化、评估指标、梯度消失和梯度爆炸深度学习——前向传播与反向传播、神经网络(前馈神经网络与反馈神经网络)、常见算法概要汇总万字长文解读…

C#版使用融合通信API发送手机短信息

目录 功能实现 范例运行环境 实现范例 类设计 类代码实现 调用范例 总结 功能实现 融合云通信服务平台,为企业提供全方位通信服务,发送手机短信是其一项核心功能,本文将讲述如何使用融合云服务API为终端手机用户发送短信信息&#xf…

第四十五章 Vue之Vuex模块化创建(module)

目录 一、引言 二、模块化拆分创建方式 三、模块化拆分完整代码 3.1. index.js 3.2. module1.js 3.3. module2.js 3.4. module3.js 3.5. main.js 3.6. App.vue 3.7. Son1.vue 3.8. Son2.vue 四、访问模块module的state ​五、访问模块中的getters ​六、mutati…

如何解决不能将开发板连接到虚拟机的问题(连接显示灰色,不能选中)

-- 如果连接上rk3588单片机,虚拟机无法来连接,如何更改 -- 先将虚拟机关机 -- 将虚拟机的配置文件以文本文件的形式打开 -- 再将所有的FALSE改为TRUE即可 -- 然后再次打开虚拟机即可

什么是白盒测试

一、什么是白盒测试 白盒测试又称结构测试、逻辑驱动测试或基于代码的测试。 白盒测试是一种测试用例设计方法,盒子指的是被测试的软件,白盒指的是盒子是可视的,即清楚盒子内部的东西以及里面是如何运作的。 "白盒"法需要测试者…

图形 2.6 伽马校正

伽马校正 B站视频:图形 2.6 伽马校正 文章目录 伽马校正颜色空间传递函数 Gamma校正校正过程为什么需要校正?CRT与转换函数 为什么sRGB在Gamma 0.45空间? 人对亮度的敏感韦伯定律中灰值 线性工作流不在线性空间下进行渲染的问题统一到线性空…

Android setContentView执行流程(一)-生成DecorView

Android setContentView执行流程(一)-生成DecorView Android setContentView执行流程(二)-将布局添加到mContentParent setContentView的流程主要就是讲在Activity的onCreate方法中调用setContentView方法之后,我们自定义的xml文件加载的过程,学习它可以…

【计算机网络】【网络层】【习题】

计算机网络-网络层-习题 文章目录 13. 图 4-69 给出了距离-向量协议工作过程,表(a)是路由表 R1 初始的路由表,表(b)是相邻路由器 R2 传送来的路由表。请写出 R1 更新后的路由表(c)。…

图像处理实验四(Adaptive Filter)

一、Adaptive Filter简介 自适应滤波器(Adaptive Filter)是一种能够根据输入信号的统计特性自动调整自身参数以达到最佳滤波效果的滤波器。它广泛应用于信号处理领域,如信道均衡、系统识别、声学回波抵消、生物医学、雷达、波束形成等模块。 …

typedef 与 extern 的结合:一场误解的澄清

typedef 与 extern 的结合:一场误解的澄清 一、typedef 的基本用法二、extern 的基本用法三、typedef 与 extern 的结合:一场误解的澄清示例二:使用 extern 声明外部变量示例三:错误的用法:尝试在 typedef 中使用 extern四、总结在C语言编程的世界里,typedef和extern是两…

Qt_day5_常用类

常用类 目录 1. QString 字符串类(掌握) 2. 容器类(掌握) 2.1 顺序容器QList 2.2 关联容器QMap 3. 几种Qt数据类型(熟悉) 3.1 跨平台数据类型 3.2 QVariant 统一数据类型 3.3 QStringList 字符串列表 4. QD…

HashMap的put流程知道吗

HashMap 的 put 方法算是 HashMap 中比较核心的功能了,复杂程度高但是算法巧妙,同时在上一版本的基础之上优化了存储结构,从链表逐步进化成了红黑树,以满足存取性能上的需要。本文逐行分析了 put 方法的执行流程,重点放…