JVM相关面试题

【面试题一】谈谈JVM内存模型

JVM内存区域的划分,之所以划分是为了JVM更好的进行内存管理。就好比一间卧室,这块放床,这块放个电脑桌,每块地方各自有各自的功能,床用来睡觉,电脑桌用来办公打游戏。而JVM划分的内存区域也是各自有各自的用处。首先当JVM启动时,会申请一块很大的空间,然后把这块空间分成几块较小的区域,如下图。

在这里插入图片描述

  1. 本地方法栈:是用来存储JVM内部的native方法之间调用的关系的。本地方法栈是JVM内部C++写的代码。
  2. 虚拟机栈:是给Java代码使用的栈,存储的是Java方法之间调用的关系。可以认为包含了多个元素,每个元素是一个方法,一个元素又可以称为“栈帧”,一个栈帧里会包含**“方法的入口地址、方法的返回地址、方法参数和局部变量”**,并且一个线程拥有一个栈,栈是线程私有的。
  3. 程序计数器:描述的是一个线程当前执行到了哪条指令,每个线程有一份。
  4. 堆:是JVM里最大的一块空间,存储的是NEW出的对象,类的成员变量。一个进程有一份,多个线程共享一份堆。
  5. 元数据区:在Java8之前是称为“方法区”的,在Java8之后才成为“元数据区”,存储的是类对象、静态成员变量和常量池。一个进程有一份,多个线程共享一份。

注意一下哈,此处总结为:栈存储的是局部变量,堆储存的是普通成员变量,元数据区存储的是静态成员变量。

【面试题二】谈谈JVM类的加载过程

类加载就是找到.class文件,然后把文件内容从硬盘里读取到内存中。大概流程如下:

在这里插入图片描述

  1. 加载:就是找到.class文件,打开文件,然后把文件内容从硬盘读到内存中,最后完成加载得到类对象。
  2. 验证:即验证.class文件的格式是否正确,.class文件是一个二进制的文件。在官方的虚拟机规范文档里有描述这个二进制文件长啥样。
  3. 准备:给类对象分配一个内存空间,也就是在元数据区里占个位置,此时会把静态成员变量初始为0值。
  4. 解析:初始化字符串常量,把符号引用转为直接引用。
  5. 初始化:此时才会真正的给类对象的内进行初始化,也就是进行成员的初始化,执行代码块、静态代码块和加载父类。

解释一下符号引用和直接引用是什么:字符串常量得有一块内存空间进行存放,然后使用一个引用来指向这个内存空间的起始地址,但是在类加载前,字符串常量是存放在.class文件里的,此时并未分配空间,也就是这个引用其实指向的是一个类似于“偏移量”或者是“占位符”的一个东西,这个就是“符号引用”。而当类加载后,字符串常量才会被真正的分配一个内存空间,此时这个引用才会指向这个内存空间的起始地址,这个就称为“直接引用”,这个过程就是“符号引用”转为“直接引用”。

【面试题三】一个类什么时候会被加载

只有当一个类被真正使用到了才会被加载,并不是当Java程序一启动就把所有类进行加载。比如进行构造类的实例,调用类的静态方法或者静态属性都会执行类加载。当使用子类时会先加载父类,并且一个类一旦被加载后,不会被重复加载。

【面试题四】谈谈双亲委派模型

​ 双亲委派模型描述的是如何找到.class文件。JVM提供了三个类加载器,BootStrapClassLoard负责加载标准库中的类,ExtensionClassLoard负载加载JVM扩展库中的类。(扩展库就是Java规范之外,由实现JVM的厂家提供的额外功能的库)ApplicationClassLoard负责加载第三方库的类和程序猿自定义的类。这三个类存在“父子关系”,即每个类里有个parent属性,这个属性里存储的是自己的“父·类加载器”。Application的父类加载器是Extension,Extension的父·类加载器是Bootstrap。

​ 当进行类加载时,会先Application开始,不过Application会把执行加载的任务交给自己的父类,只有当自己的父类加载完成后或者没有父类,自己才会真正的执行加载任务,于是此时任务交给了Extension,而Extension又把任务交给了BootStrap,最后BootStrap由于没有父类加载器,于是BootStrap开始执行类加载,去标准库里找到相关的类进行加载,如果没有找到剩余的类,就会把任务交给自己的子类加载,此时Extension会执行加载任务,会去扩展库中找到相关的类进行加载,最后把任务交给Application加载,去第三方库和自定义的类里找到并且加载,如果剩余的类没有找到,此时会报一个“类找不到”这样的异常。

​ **为什么会有这样的顺序?**之所以有这样的顺序是由于JVM的实现是按照类似于递归的方式实现的,于是就导致了从上到下又从下到上的顺序,其次也是为了保证BootStrap先加载,Application最后加载,这样可以避免程序猿自定义的一些类,引起了JVM内部bug。比如自定义写了个java.lang.String,按照上述流程就是先加载的是标准库里的String类,就不会导致JVM内部已经实现的代码出现bug。类加载器也可以自定义,并且可以存放在三个类加载器的任意位置。

【面试题五】谈谈Java的垃圾机制

GC垃圾回收就是把不用的内存给自动释放掉,这样的好处是写代码简单,不容易出错,但是会额外占用系统资源。如果当内存垃圾很多了,此时触发了GC操作,就会占用很多的系统资源,并且GC的有些操作会有一些锁操作,此时就会导致正常执行的业务代码无法执行,这种问题就称为“STW“问题(Stop The World)

GC进行垃圾回收是以“对象”单位回收的。此处可以把对象分为三类:一是正在使用的内存,二是不用了但未被回收的内存,三是未被分配内存的。像一部分在使用一部分未使用的对象是不会被回收的,比如一个对象里有些属性还在使用,而有些属性已经用完了。GC的具体工作流程是:先找到垃圾,然后进行释放。

  • 找到垃圾:使用的是可达性分析策略。JVM存有一份所有对象的名单,可达性分析就是把所有对象看作为一棵树,从根节点开始遍历,能访问到的就标记为“可达”,访问不到的标记为“不可达”,然后把这些不可达的对象当成垃圾给释放掉,可达性遍历会进行周期性的遍历。因为Java里的对象都是通过引用来指向进行访问内存的,而一个对象里的成员又可以通过引用指向另一个对象,因此就会构成一个类似于树形的结构,可达性分析的根节点/起点称为GCroots,GCroots可以是栈上的局部变量、常量池的对象和静态成员变量

  • 对象的释放/垃圾释放:进行垃圾的释放有以下几种策略

    1. 标记清除:标记清除就是把标记为垃圾的空间直接释放掉,简单高效,不过会导致内存碎片问题,由于Java申请空间都是连续性的,所以当申请一个较大的空间时,可能就会申请失败。

    2. 复制算法:解决了内存碎片的问题, 复制算法就是把一个空间分成两部分,每次只用一半的内存,然后当进行垃圾回收时,把不是垃圾的对象复制到另一半没有使用的内存里,由于对象是按顺序复制过来的,所以不会有内存碎片问题。但是复制算法的成本比较高,当垃圾较少时,有效对象多,此时触发复制算法,复制的成本就比较大。

      在这里插入图片描述

      进行了复制算法,把左侧对象1(垃圾)进行了删除,此时右侧内存是顺序存放的,所以内存空间是连续的,下次比如对象2变成了垃圾,就会把对象3复制到左侧内存空间,然后直接把对象2进行释放。

      在这里插入图片描述

    3. 标记整理:标记整理解决了空间利用率低的问题,类似于顺序表删除元素或者搬运元素。比如内存里有1、2、3、4、5、6此时2、4、6为垃圾,就把3、5往前进行搬运,把2、4覆盖掉,最后把6直接释放。

      在这里插入图片描述

    4. 分代回收:基于前面几种策略,设计出一个复合型的策略,即把垃圾回收分为不同的场景,每个场景使用不同的算法。Java对象的生命周期一般比较长,要么就很短,所以可以根据生命周期的长短,引入一个“年龄”的概念,单位是熬过GC的轮次,即当GC扫描一轮后,当前对象存活下来就把年龄+1,每个刚NEW出来的对象年龄为0。JVM把堆划分出一系列的区域,先把一整个空间划分为两部分,一部分为新生代,另一部分为老年代,在新生代里划分出一个较大的伊甸区,和两个同等大小的幸存区,伊甸区存放刚NEW出来的新对象,当熬过一轮GC后,使用复制算法把对象复制到第一个幸存区,到了幸存区后,当前对象需要继续接受GC周期性的扫描,当第二次熬过GC轮次后,从第一个幸存区复制到第二个幸存区,这样来回两个幸存区复制,当对象的年龄达到15时,就复制到老年代,进入老年代后,GC就会降低扫描的频率,因为当进入老年代说明当前对象生命周期很长,短时间内不会成为垃圾,当老年代里的对象称为垃圾时,会使用标记整理的策略进行垃圾释放。

    在这里插入图片描述

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

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

相关文章

docker常用命令和环境部署详解

Docker是一个开源的容器化平台,它允许开发者打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。以下是Docker的一些常用命令和环境部署的详解: Docker常用命令: 查看…

C++——基础语法(3):内联函数、auto关键字、基于范围的for循环、空指针nullptr

6. 内联函数 在函数前加入inline修饰即可将函数变为内联函数。所谓内联函数,就是在编译时C编译器会将函数体在调用内联函数的地方展开,从而省去了调用函数的栈帧开销,提高程序运行效率。 inline int Add(int a, int b) {return a b; } int …

什么是企业级服务器?

服务器在应用层次方面分为入门级服务器、工作组级服务器、部门级服务器和企业级服务器。那么什么是企业级服务器,具体包含哪些内容呢,今天小编就带领大家大概的了解一下吧! 企业级服务器是高级服务器之一,服务器性能比入门级服务器…

SpringBoot源码解读与原理分析(三十三)SpringBoot整合JDBC(二)声明式事务的生效原理和控制流程

文章目录 前言10.3 声明式事务的生效原理10.3.1 TransactionAutoConfiguration10.3.2 TransactionManagementConfigurationSelector10.3.3 AutoProxyRegistrar10.3.4 InfrastructureAdvisorAutoProxyCreator10.3.5 ProxyTransactionManagementConfiguration10.3.5.1 Transactio…

Datawhale-Sora技术原理分享

目录 Sora能力边界探索 Sora模型训练流程 Sora关键技术拆解 物理引擎的数据进行训练 个人思考与总结 参考 https://datawhaler.feishu.cn/file/KntHbV3QGoEPruxEql2c9lrsnOb

道可云元宇宙每日资讯|沙特推出世界首个国家级“元宇宙”平台

道可云元宇宙每日简报(2024年2月27日)讯,今日元宇宙新鲜事有: 沙特推出世界首个国家级“元宇宙”平台 据 Gulf News 等媒体报道,沙特阿拉伯文化部近日宣布上线全球首个国家级“元宇宙”平台,该平台由先进…

题目 1282: 公交汽车

题目描述: 一个特别的单行街道在每公里处有一个汽车站。顾客根据他们乘坐汽车的公里使来付费。例如下表就是一个费用的单子。 没有一辆车子行驶超过10公里&#xff0c;一个顾客打算行驶n公里&#xff08;1< n< 100&#xff09;&#xff0c;它可以通过无限次的换车来完…

袁庭新ES系列12节 | Elasticsearch高级查询操作

前言 上篇文章讲了关于Elasticsearch的基本查询操作。接下来袁老师为大家带来Elasticsearch高级查询部分相关的内容。Elasticsearch是基于JSON提供完整的查询DSL&#xff08;Domain Specific Language&#xff1a;领域特定语言&#xff09;来定义查询。因此&#xff0c;我们有…

消息中间件篇之Kafka-消息不丢失

一、 正常工作流程 生产者发送消息到kafka集群&#xff0c;然后由集群发送到消费者。 但是可能中途会出现消息的丢失。下面是解决方案。 二、 生产者发送消息到Brocker丢失 1. 设置异步发送 //同步发送RecordMetadata recordMetadata kafkaProducer.send(record).get();//异…

【Java程序设计】【C00296】基于Springboot的4S车辆管理系统(有论文)

基于Springboot的4S车辆管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的4S店车辆管理系统 本系统分为销售员功能模块、管理员功能模块以及维修员功能模块。 管理员功能模块&#xff1a;管理员登录进入4S…

Langchain 加载网络信息实现RAG以及UnstructuredURLLoader的使用

以下实现了从 wikipedia 加载 Android 的网页然后保存在本地的向量数据库&#xff0c;然后通过上下文发给大模型&#xff0c;让他来总结什么是android 。 from langchain_community.vectorstores import Chroma from langchain_core.prompts import ChatPromptTemplate from l…

少儿编程热潮背后的冷思考、是不是“智商税”?

在科技飞速发展的今天&#xff0c;编程已成为一项基础技能&#xff0c;如同数学和语言一样&#xff0c;被认为是未来社会的重要通行证。随之而来的是少儿编程教育的火爆&#xff0c;各种编程班、在线课程如雨后春笋般涌现&#xff0c;吸引了无数家长的目光。然而&#xff0c;这…

【JS】【Vue3】【React】获取滚轮位置的方法:JavaScript、Vue 3和React示例

目录 使用JavaScript原生方法在Vue 3中获取滚轮位置在React中获取滚轮位置 随着Web应用程序的发展&#xff0c;滚轮位置的获取变得越来越重要&#xff0c;可以用于实现页面的滚动效果、导航条的隐藏和显示等功能。本文将探讨在JavaScript、Vue 3和React中获取滚轮位置的不同方法…

C语言——switch 语句的基本格式是什么?

一、问题 C语⾔中有两个构成选择结构的语句&#xff0c;即构成双分⽀的让if..else 语句和构成多分⽀的 switch..case 语句&#xff0c;switch 语句的基本格式是什么&#xff1f; 二、解答 switch (表达式) { case 常量表达式 1:语句1;break;case 常量表达式 n:语句n;break;de…

嵌入式学习day26 Linux

1.exec函数族 extern char **environ; int execl(const char *path, const char *arg, ... /* (char *) NULL */); int execlp(const char *file, const char *arg, ... /* (char *) NULL */); int execle(const char *…

【深度好文】simhash文本去重流程

对于类似于头条客户端而言,推荐的每一刷的新闻都必须是不同的新闻,这就需要对新闻文本进行排重。传统的去重一般是对文章的url链接进行排重,但是对于抓取的网页来说,各大平台的新闻可能存在重复,对于只通过文章url进行排重是不靠谱的,为了解决这个痛点于是就提出了用simh…

测试环境搭建整套大数据系统(七:集群搭建kafka(2.13)+flink(1.14)+dinky+hudi)

一&#xff1a;搭建kafka。 1. 三台机器执行以下命令。 cd /opt wget wget https://dlcdn.apache.org/kafka/3.6.1/kafka_2.13-3.6.1.tgz tar zxvf kafka_2.13-3.6.1.tgz cd kafka_2.13-3.6.1/config vim server.properties修改以下俩内容 1.三台机器分别给予各自的broker_id…

MapGIS农业信息化解决方案(2)

农业资源采集与调查 农业各项生产活动与农业资源息息相关,对农业资源进行调查,摸清农业家底, 为构筑农业“一张图”核心数据库奠定数据基础。MapGIS 农业资源采集与调查系统集成遥感、手持终端等调查技术,为农业资源采集提供实用、简捷的采集调查和信息录入工具,实现农田…

PCB设计十大黄金准则

PCB设计十大黄金准则 控制走线长度控制走线长度&#xff0c;顾名思义&#xff0c;即短线规则&#xff0c;在进行PCB设计时应该控制布线长度尽量短&#xff0c;以免因走线过长引入不必要的干扰&#xff0c;特别是一些重要信号线&#xff0c;如时钟信号走线&#xff0c;务必将其…

GoLevelDB构建数据字典

GoLevelDB 是一个开源的键值存储数据库&#xff0c;可以用于构建数据字典&#xff0c;下面是一些示例代码&#xff0c;展示了如何使用 GoLevelDB 来生成数据字典。 首先&#xff0c;你需要在 Go 中导入 GoLevelDB 包&#xff0c;并创建一个数据库实例。可以使用 leveldb.OpenF…