【JVM】之常见面试题

news2024/10/6 8:23:14

文章目录

  • 1.JVM中的内存区域划分
  • 2.JVM的类加载机制
    • 2.1 加载
    • 2.2 验证
    • 2.3 准备
    • 2.4 解析
    • 2.5 初始化
    • 2.6 类加载的时机
  • 3 类加载器
  • 4.双亲委派模型
  • 5.JVM中的垃圾回收策略
    • 5.1 找谁是垃圾
      • 5.1.1 引用计数法
      • 5.1.2 可达性分析法
    • 5.2 释放垃圾
      • 5.2.1 标记清除算法
      • 5.2.2 复制算法
      • 5.2.3 标记整理算法
      • 5.2.4 分代算法

1.JVM中的内存区域划分

JVM就是一个Java进程,Java进程会从操作系统这里申请一大块内存空间,给Java代码来使用。
而这一大块内存空间又可以进一步细分为以下几个最核心的内存区域:

  • 堆:存放的是new出来的对象,即成员变量。
  • 栈:存放的是方法与方法之间的调用关系,即局部变量。
  • 方法区(旧)/元数据区(新):存放的是类加载之后的类对象(.class,Test.class),即静态变量。

这块的主要考点就是给一段代码,判断某个变量处于内存中的哪个位置,需要注意是的,我们是通过变量的形态(成员变量,局部变量,静态变量)来判断,而不是通过变量的类型来判断。

例如下面的例子:

  void func() {
    Test t = new Test();
 }

在这里插入图片描述
接下来我们就系统的介绍一下JVM运行时数据区,也叫JVM的内存布局。按照 Java 的虚拟机规范,可以细分为程序计数器、虚拟机栈、本地方法栈、堆、方法区等,如下图:
在这里插入图片描述
其中堆和方法区在一个JVM进程中只有一份,而栈(虚拟机栈和本地方法栈)和程序计数器则是有多份的,每一个线程有一份。

  • 程序计数器 : 也叫PC寄存器,用途是记录当前程序执行到哪个指令了,它是一个简单的long类型变量,里面存了一个内存地址,这个内存地址就是下一个要执行的字节码的内存地址。
  • Java虚拟机栈:通常就是指”栈“,它的生命周期和线程一样,当线程执行一个方法时,会创建一个对应的栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息,然后栈帧会被压入栈中。当方法执行完毕后,栈帧会从栈中移除。
  • 本地方法栈:是给JVM内部的本地方法使用的(JVM内部通过C++实现的方法)。
  • :堆(heap)是 JVM 中最大的一块内存区域,被所有线程共享,在 JVM 启动时创建,主要用来存储对象的。
  • 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法区也是所有线程共享的。

2.JVM的类加载机制

.class 文件需要加载到虚拟机中之后才能运行和使用,类加载的过程就是将.class文件加载到内存中得到类对象的过程。其中类加载的过程分为五步,即加载→验证→准备→解析→初始化,如下图所示:
在这里插入图片描述

2.1 加载

加载阶段就是查找并加载类的二进制数据(.class文件),在加载阶段,JVM做三件事情:

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

2.2 验证

这一阶段的目的是确保 Class 文件的字节流中包含的信息符合《Java 虚拟机规范》的全部约束要求,保证这些信息被当作代码运行后不会危害虚拟机自身的安全。验证包括了:文件格式验证(二进制文件)、字节码验证,符号引用验证

2.3 准备

在准备阶段,JVM会给类对象分配内存空间并设置初始值,初始值为数据类型的默认初始值,如0,0L,false,null等。

2.4 解析

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

其中符号引用就是字符串常量,它在.class文件中已经存在了,但它们之间只知道彼此的相对位置(偏移量),并不知道自己在内存中的实际位置,而当真正加载到内存中的时候,就会把字符串常量填充到特定的位置上,字符串常量之间的相对位置还是一样的,但此时它们有了实际的内存地址,此时的字符串常量就是直接引用了(Java中的普通引用)。

2.5 初始化

初始化阶段就是针对类对象进行初始化(初始化静态成员,执行静态代码块,如果该类还有父类还需加载它的父类)。

2.6 类加载的时机

JVM 启动的时候,并不会一次性加载所有的类,而是根据需要去动态加载。也就是说,大部分类在具体用到的时候才会去加载,这样对内存更加友好。
那么什么是需要的时候呢?

  1. 创建了这个类的实例
  2. 使用了这个类的静态方法/静态属性
  3. 使用子类,也会触发父类的加载

3 类加载器

在介绍双亲委派模型之前,我们需要先知道JVM加载类时需要用到一组特殊的模块,即类加载器。
类加载器(ClassLoader)用于动态加载 Java 类到 Java 虚拟机中。主要有四种类加载器:

  1. 启动类加载器(Bootstrap ClassLoader)负责加载Java标准库中的类。

  2. 扩展类加载器(Extension ClassLoader):负责加载一些非标准的但是Sum/Oracle扩展的类

  3. 应用程序类加载器(Application ClassLoader):负责加载项目中自己写的类以及第三方库中的类。

  4. 用户自定义类加载器 (User-Defined ClassLoader),我们可以通过继承java.lang.ClassLoader类来创建自己的类加载器。

4.双亲委派模型

在上面我们介绍了JVM类加载的过程,而这就不得不提到一个重要的考点了——双亲委派模型。
它发生在第一步加载中找.class文件的时候,是 Java 类加载机制中的一个重要概念。这种模型指的是一个类加载器在尝试加载某个类时,首先会将加载任务委托给其父类加载器去完成。只有当父类加载器无法完成这个加载请求(即它找不到指定的类)时,子类加载器才会尝试自己去加载这个类。 如下图所示:

在这里插入图片描述

  • 当一个类加载器需要加载某个类时,它首先会请求其父类加载器加载这个类。
  • 这个过程会一直向上递归,也就是说,从子加载器到父加载器,再到更上层的加载器,一直到最顶层的启动类加载器(Bootstrap ClassLoader)。
  • 启动类加载器会尝试加载这个类。如果它能够加载这个类,就直接返回;如果它不能加载这个类(因为这个类不在它的搜索范围内),就会将加载任务返回给委托它的子加载器。
  • 子加载器接着尝试加载这个类。如果子加载器也无法加载这个类,它就会继续向下传递这个加载任务,依此类推。
  • 这个过程会继续,直到某个加载器能够加载这个类,或者所有加载器都无法加载这个类,最终抛出 ClassNotFoundException。

5.JVM中的垃圾回收策略

垃圾回收(Garbage Collection,GC),顾名思义就是释放垃圾占用的空间,防止内存爆掉。有效的使用可以使用的内存,对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收。
而垃圾回收之前我们需要先清楚谁是垃圾,谁不是垃圾,即GC分为了两步,先是找谁是垃圾,再对垃圾进行释放。

5.1 找谁是垃圾

常用的垃圾判断算法有引用计数算法,可达性分析算法。

5.1.1 引用计数法

引用计数法:给对象增加一个引用计数器,每当有一个地方引用该对象时,计数器+1,当引用失效时,计数器-1,任何时候计数器为 0 的对象就是不可能再被使用的。
优点:实现简单,效率高
缺点:无法解决循环引用的问题

5.1.2 可达性分析法

这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,即从 GC Roots 到该对象节点不可达,则证明该对象是需要垃圾收集的。
在这里插入图片描述
可以作为GC Roots的对象:

  • 栈上的局部变量(每个栈的每个局部变量都是起点)
  • 常量池中引用的对象
  • 方法区中,静态变量引用的对象

5.2 释放垃圾

在确定了哪些垃圾可以被回收后,垃圾收集器要做的事情就是进行垃圾回收,如何高效地进行垃圾回收呢?

5.2.1 标记清除算法

标记清除算法,分为 2 部分,先把内存区域中的这些对象进行标记,哪些属于可回收的标记出来,然后把这些垃圾拎出来清理掉。
在这里插入图片描述

优点:实现简单。

缺点:产生大量不连续的内存碎片。当我们想申请一块连续的较大的内存时,可能就申请不到。

5.2.2 复制算法

在标记清除算法上演化而来的,用于解决标记清除算法的内存碎片问题。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。
在这里插入图片描述
优点:执行效率高,没有内存碎片的问题。

缺点:空间利用率低,因为复制算法每次只能使用一半的内存。

5.2.3 标记整理算法

标记整理算法,标记过程仍然与标记清除算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,再清理掉端边界以外的内存区域。
在这里插入图片描述
优点:解决了内存碎片问题,比复制算法空间利用率高。

缺点:因为有局部对象移动,所以效率不是很高。

5.2.4 分代算法

当前虚拟机的垃圾收集都采用分代收集算法,是根据对象存活周期的不同将内存分为几块。一般将 Java 堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。
由于新生代存放的大部分数据是朝生夕死的,所以新生代使用的是效率最高的复制算法;而老生代使用的是标记-清除或标记-整理算法,如果标记-清除可以满足需要那么就使用效率更好的标记-清除算法,如果标记-清除算法不能满足需要就使用标记-整理算法。

在这里插入图片描述
今天的分享到这里就结束了,感谢支持!

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

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

相关文章

GoogleDeepMind联合发布医学领域大语言模型论文技术讲解

Towards Expert-Level Medical Question Answering with Large Language Mod 这是一篇由Google Research和DeepMind合作发表的论文,题为"Towards Expert-Level Medical Question Answering with Large Language Models"。 我先整体介绍下这篇论文的主要内容&#x…

[CAN] 创建解析CAN报文DBC文件教程

👉本教程需要先安装CANdb软件,[CAN] DBC数据库编辑器的下载与安装 🙋前言 DBC(全称为Database CAN),是用于描述单个CAN网络中各逻辑节点的信息。 DBC是汽车ECU(Electronic Control Unit,电子控制单元&…

批量文件重命名软件

因为日常用电脑的时候,经常都会遇到需要对当前目录下的文件,进行重命名。最好是按照自己的规则上来进行批量重命名。我试了几款软件,都感觉不是很好,不是要收费,就是各种乱七八糟的流氓广告。本想着干脆自己写算了,在绝望之际,找到了这款软件,亲测,确实还用,特别是满…

python 10个高频率的自动化脚本(干货,速度收藏)

1. 文件操作:自动备份文件 场景:每日自动备份重要文件到指定目录。 import shutilimport datetimedef backup_file(src, dst_folder): now datetime.datetime.now().strftime(%Y%m%d%H%M%S) dst_path f"{dst_folder}/backup_{now}_{src.s…

bugku---misc---ping

1、下载附件,解压后是一个流量包 2、用wireshark分析,发现都是清一色的icmp报文,只能看看内容。 3、点了几条流量,发现有个地方连起来是flag 4、最终将所有的拼起来,得到flag flag{dc76a1eee6e3822877ed627e0a04ab4a}…

CleanMyMac X软件最新版下载【安装详细图文教程】

​CleanMyMac X是一款专业的Mac清理软件,可智能清理mac磁盘垃圾和多余语言安装包,快速释放电脑内存,轻松管理和升级Mac上的应用,同时CleanMyMac X可以强力卸载恶意软件,修复系统漏洞,一键扫描和优化Mac系统…

nginx rewrite地址重写

常用的nginx正则表达式 ^匹配以...开头的字符串$匹配以...结尾的字符串^$^$表示空行*匹配前面的字符0次或者多次(通配符*表示任意数量的任意字符)匹配前面的字符1次或多次?匹配前面的字符0次或1次.匹配除了“\n”之外的任意单个字符,[.\n]表…

第十五届蓝桥杯大赛 国赛 pb组F题【括号与字母】(15分) 栈的应用

博客主页:誓则盟约系列专栏:IT竞赛 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ 试题F:括号与字母 【问题描述】 给定一个仅包含小写字母和括号的字符串 S …

少有人走的低风险创业之路:一人公司

大家好,我是弗雷!在前面的文章中,深入讨论了老板和员工思维的本质不同,非常值得普通人一看。接下来,我们将继续分享一人公司的话题。 一提到创业就认为风险很大? 只懂埋头苦干,不懂创新营销怎…

rocketmq-5.1.2的dleger高可用集群部署

1、背景 原先为5.0.0版本,因检查出有漏洞,升级到5.1.2版本。 【Rocketmq是阿里巴巴在2012年开发的分布式消息中间件,专为万亿级超大规模的消息处理而设计,具有高吞吐量、低延迟、海量堆积、顺序收发等特点。在一定条件下&#xf…

如何手动实现multiSetIfAbsent、multiExpire

👽System.out.println(“👋🏼嗨,大家好,我是代码不会敲的小符,目前工作于上海某电商服务公司…”); 📚System.out.println(“🎈如果文章中有错误的地方,恳请大家指正!共同进步,共同成长✊”); 🌟System.out.println(“💡如果文章对您有所帮助,希望您可以三…

C#操作MySQL从入门到精通(22)——创建表与操纵表

前言 我们新建数据库以后,最需要做的就是创建表,对数据库的操作绝大多数情况下都是都对表的操作,本文就是讲解如何创建表以及修改表中的列,修改表名等操作。由于创建表的方法基本上有两种,一种是使用带有界面的工具比如Navicate来创建表,另一种是使用sql语句来创建表,实…

rv1126-rv1109-串口显示路径不变化

串口只有#, 后来看了教程改成如下 但是没有变化,那个路径都只显示rootLonbon# 于是最后改成了这样 因为:

CSS函数: 实现数据限阈的数字函数

CSS函数中提供了几个比较实用的数字函数,它可以帮助我们实现一定的数学计算功能。常见的数字函数目前提供了五个:calc()、max()、min()和clamp()函数。其基本实现功能如下: calc():允许在声明 CSS 属性值时执行一些计算。max()&a…

数据结构 —— 堆

1.堆的概念及结构 堆是一种特殊的树形数据结构,称为“二叉堆”(binary heap) 看它的名字也可以看出堆与二叉树有关系:其实堆就是一种特殊的二叉树 堆的性质: 堆中某个结点的值总是不大于或不小于其父结点的值&…

ColorEasyDuino上手指南

介绍 ColorEasyDuino是嘉立创推出的一块Aduino开发板(类似物),具有丰富的外设接口:uart、i2c、spi、adc、pwm等;开发板设计参考原型是Arduino Uno,采用的芯片是ATMEGA328P,它的外观设计比较紧凑…

⌈ 传知代码 ⌋ MonoCon解读与复现

💛前情提要💛 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间,对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

【Gradio】快速入门

https://www.gradio.app/ Gradio 是一个开源 Python 软件包https://github.com/gradio-app/gradio ,可以让你快速为机器学习模型、API 或任何任意 Python 函数创建一个演示或网络应用程序。然后,您就可以使用 Gradio 内置的分享功能,在几秒钟…

ROS2底层机制源码分析

init ->init_and_remove_ros_arguments ->init ->Context::init 保存初始化传入的信号 ->install_signal_handlers→SignalHandler::install 开线程响应信号 ->_remove_ros_arguments 移除ros参数 ->SingleNodeManager::instance().…

D-Bus——system 调用session 报错

以下代码是一个 session 服务和 systemd 服务 demo &#xff1a; systemd DBus #include <QCoreApplication> #include <QDBusConnection> #include <QDBusInterface> #include <QDBusError> #include <QDebug>class TestObject : public QObje…