JVM高频面试题(2023最新版)

JVM面试题

1、JVM内存区域

在这里插入图片描述

Jvm包含两个子系统和两个组件。

1.1子系统

Class loader(类加载器):根据给定的全限定名类名(java.lang.object)来装载class文件到Runtime data area(运行时数据区)的method(方法区)。

Execution engine(执行引擎):执行classes中的指令。

Native Interface(本地接口):与native libraries交互,是其他编程语言交互的接口。

Runtime data area(运行时数据区域):JVM内存

作用

  • 通过编译器将Java代码转换为字节码
  • 类加载器(class loader)再将字节码加载到内存中(运行时数据区)的方法区(method)
  • 字节码文件只是JVM的一套指令集规范,不能直接交给底层操作系统执行,需要特定的命令解析器执行引擎(Execution engine),将字节码翻译成底层系统指令
  • 再交给CPU执行
  • 过程中需要调用其他语言的本地库接口(native interface)实现整个程序的功能

类的加载:将class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆上创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。

1.2 运行时数据区

在这里插入图片描述

程序计数器:当前线程所执行的字节码的行号指示器。通过改变这个计数器的值,选取下一条需要执行的字节码指令。

Java虚拟机栈:存储局部变量表、操作数栈、动态连接、方法出口等信息。(服务JAVA方法)

本地方法栈:为虚拟机Native方法服务的,这些方法底层是C语言编写,直接与操作系统对接的方法。

:内存中最大的一块,被所有线程共享,几乎所有对象实例都在这里分配内存。包括静态对象。

方法区:存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。

1.2.1 堆和栈的区别

物理地址

堆的物理地址分配对象是不连续的。性能较慢。在GC时考虑到不连续的分配,因此有各种算法(标记清除、复制、标记压缩、分代等)

栈使用的是数据结构中的栈,先进后出,物理地址分配时连续的,性能快。

内存分别

堆因为分配不是连续的,分配的内存在运行期才确认,大小不固定。

栈是连续的,分配的内存大小在编译器就确认,大小是固定的。

存放的内容

堆存放对象的实例和数组,更关注数据的存储。

栈存放局部变量,操作数栈,返回结果。更关注程序方法的执行。

可见度

堆对于整个应用程序共享、可见。

栈只对于线程可见,线程私有。生命周期和线程相同。

1.2.2 队列和栈的区别
  • 队列:入队,出队;栈:进栈,出栈。
  • 队列是队尾入队,队头出队,先进先出,两边都可操作;栈是先进后出,进栈出栈都在栈顶进行。
1.2.3 对象的创建过程
  • 虚拟机收到new指令,先检查常量池是否已加载对应的类
  • 如果没有,先执行相应的类加载(java文件转class,存入运行时数据区),类加载通过后分配内存
  • 若堆中的内存是绝对规整的,使用“指针碰撞”方式分配内存。
  • 若不是规整的,从空闲列表中分配
1.2.4 内存溢出异常

不再被使用的对象或变量一直被占据在内存中。理论上Java有GC垃圾回收机制,不再被使用的对象会被GC自动回收。但还是存在内存泄漏问题。

原因:长生命周期的对象持有短生命周期对象的引用就会导致内存泄漏。

2 垃圾收集器

2.1 垃圾回收机制

Java中,由虚拟机自行执行对象的内存释放。有一个垃圾回收线程,低优先级,在虚拟机空闲或当前堆内促不足时,触发执行,扫描那些没有被任何引用的对象,并将它们添加到需要回收的集合中,进行回收。

2.2 GC

Gabage Collection 垃圾收集,忘记或错误的内存回收会导致程序或系统的不稳定甚至崩溃。

Java提供的GC功能可以自动检测对象是否超过作用域,从而达到自动回收内存的目的。

垃圾回收的优点

  • 编写程序时,不需要考虑内存管理问题
  • Java中的对象不再有“作用域”的概念,只有引用的对象才有“作用域”
  • 垃圾回收机制有效防止了内存泄漏,有效的使用可使用的内存
  • 作为一个单独的低级别的线程运行,在不可预知的情况下对堆中已经死亡或长时间没有用过的对象进行清除和回收
  • 程序员不能实时对某个对象或所有对象调用垃圾回收器进行回收
  • 垃圾回收有分代复制、标记、增量垃圾回收

垃圾回收基本原理

对于GC来说,当对象被创建后,GC就开始监控这个对象的地址、大小、及使用情况。

通常,GC采用向图的方式记录和管理堆中的对象。通过确定哪些对象是“可达的”。当GC确定一些对象为“不可达”时,GC就有责任回收这些内存空间。

可以通过System.gc(),通知GC运行,但并不保证GC一定会运行。

怎么判断对象是否可以被回收?

  • 引用计数器法:为每个对象创建一个引用计数,有对象引用时+1,引用被释放时-1,当计数器为0时,就可以回收了。但是不能解决循环引用的问题
  • 可达性分析算法:GC Roots开始向下搜索,当一个对象到GC Roots没有任何引用链相连时,则证明可以被回收

2.3 垃圾回收算法

标记-清除法:标记无用的对象,进行清除。(其他算法几乎都是在其上进行改进)

优点:实现简单,不需要对象进行移动。

缺点:效率低,产生大量不连续的内存碎片,提高了垃圾回收的频率。

  • 标记阶段:标记出可以回收的对象
  • 清除阶段:回收被标记的对象所占用的空间

复制算法:将内存划分为两个相等的区域,每次只使用其中一个。每次遍历单个区域,将存活的对象复制到另一个区域,再清除当前区域。

优点:按顺序分配内存,运行效率高,不用考虑内存碎片

缺点:可用的内存大小只要原来的一半,对存活率高的对象频繁复制

标记-整理算法:在新生代可以使用复制算法,老年代不适合(存活频率高)。标记整理算法在标记回收对象后,将所有存活的对象压缩到内存的一段,紧凑排列,再对边界外的内存进行回收。

优点:解决了标记清理算法存在内存碎片的问题

缺点:仍需要进行局部的对象移动,一定程度上降低了效率

分代收集算法:根据对象存活周期,将内存划分为几块:年轻代、老年代、永久代。(jdk1.8后,删除了永久代,增加了元数据区)

2.4 垃圾回收器

在这里插入图片描述

Serial收集器(复制算法):新生代单线程收集器,标记和清理都是单线程,优点是简单高效。收集器回收时会暂停业务线程。

ParNew收集器(复制算法):新生代并行收集器,Serial收集器的多线程版本,多核CPU环境下比Serial性能更好。GC线程和业务线程并行。

Parallel Scavenge(复制算法):新生代并行收集器,追求高吞吐量,高效利用CPU。尽快完成程序的运算任务。jdk1.8默认收集器。GC线程和业务线程并行。

Serial Old收集器 (标记-整理算法):老年代单线程收集器,Serial收集器的老年代版本。收集器回收时会暂停业务线程。

Parallel Old收集器(标记-整理算法):老年代并行收集器,吞吐量优先,Parallel Scavenge的老年代版本。jdk1.8默认收集器。GC线程和业务线程并行。

CMS收集器(标记-清除算法):老年代并行收集器,以获取最短回收停顿时间为目标的收集器,高并发、低停顿,追求最短GC回收停顿时间。牺牲了吞度量来获得最短的停顿时间,适用于服务器响应速度高要求的应用上。因为是基于标记-清除算法,会出现大量内存碎片,此时CMS会临时采用Serial Old回收器进行垃圾清除,同时性能会下降。GC线程和业务线程并行。在启动 JVM 的参数加上“-XX:+UseConcMarkSweepGC”来指定使用 CMS 垃圾回收器。

G1收集器(标记-整理算法):Java堆并行收集器,由jdk1.7提供,基于标记整理-算法,回收范围为整个堆,而不再分新生代和老年代。区域上使用了分区算法。一边清理一部分区域,一边占用一部分区域,特别大的对象放Humongous区域,也不够了开始FullGC。

ZGC(颜色算法):分区更灵活,逻辑上部分带。每次找到特别满的区域进行清除。

垃圾回收器工作流程

新生代:老年代=1:2

新生代使用复制-算法,本身也分三个区,Eden、To Survivor、From Survivor。默认8:1:1

  • Eden+From Survivor存活的对象放入To Survivor
  • 清空Eden+From Survivor分区
  • From Survivor和To Survivor分区交换

每次在 From Survivor 到 To Survivor 移动时都存活的对象,年龄都+1,当年龄达到15(默认的)时,升级为老年代,大的对象直接放入老年代。

老年代这边,当空间占用达到某一个阈值之后,触发Full GC,此时一般使用标记整理算法。

对象优先分配到新生代的Eden区,Eden区空间不够时,进行Minor GC,还不够,则分配到老年代。

Minor GC非常频繁,回收速度也快。大对象(需要大量连续内存空间的对象)直接进入老年代。

3、虚拟机类加载机制

3.1 简述

虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验、解析和初始化,最终形成虚拟机可以直接使用的Java类型。

3.2 JVM加载Class文件的原理机制

隐式装载:程序运行过程中,碰到new等方式创建对象时,调用类装载器加载对应类到JVM中。

显示装载:通过class.forname()等方法,显示加载需要的类。

动态加载,保证基类完全加载,其他类需要的时候才加载。

3.3 类加载器

实现通过类的权限定名获取该类的二进制字节流的代码块

  1. 启动类加载器,加载Java核心类库,无法被程序直接引用。Java_HOME/lib/目录中的,被 -Xbootclasspath参数指定路径的类库。
  2. 扩展类加载器,加载Java的扩展库,Java虚拟机的实现会提供一个扩展库目录。JDK的安装目录的jre/lib/ext子目录(扩展目录)或Java. ext. dirs系统变量指定的路径中的所有类库。
  3. 系统类加载器,根据Java应用的类路径(ClassPath)来加载Java类。通常Java应用的类都是它加载的。可通过ClassLoader.getSystemClassLoader()获取它。
  4. 用户自定义类加载器,通过继承java.lang.ClassLoader类实现。

3.4 类装载的过程

  • 加载:根据路径找到对应的class文件导入。
  • 验证:检查加载的class文件的正确性。
  • 准备:给类中的静态变量分配内存空间。
  • 解析:虚拟机将常量池中的符号引用替换成直接引用的过程。
  • 初始化:对静态变量和静态代码块执行初始化工作。

3.5 双亲委派

如果一个类加载器收到了类加载的请求,首先不会自己去加载,

而是委派给父类加载器,这样所有的加载请求都会传到顶层的启动类加载器,

当父加载无法完成加载(搜索范围中没找到)时,子加载器才去尝试加载。

启动类加载器=》扩展类加载器=》系统类加载器=》自定义类加载器。

3.5.1 优点
  • 避免类重复加载(唯一性),只会在一个类加载器加载。
  • 安全性,保证Java核心类库的安全,比如自己又写了一个java.lang.String,优先会去加载核心类库中的。
  • 为模块化开发提供了基础支持,如果使用多个第三方库,可能存在同名的类。使用双亲委派机制可以保证不同的类加载器只加载自己的类,避免类名冲突。

4、JVM调优

4.1 工具

JDK的bin目录下,自带了很多监控工具。

jconsole:用于对JVM中内存、线程和类等进行监控。

jvisualvm:内存快照、线程快照、程序死锁、监控内存变化、GC变化等。

4.2 参数

  • -Xms2g:初始化推大小为 2g;
  • -Xmx2g:堆最大内存为 2g;
  • -XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4;
  • -XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2;
  • –XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合;
  • -XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合;
  • -XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合;
  • -XX:+PrintGC:开启打印 gc 信息;
  • -XX:+PrintGCDetails:打印 gc 详细信息。
    urvivor 比例为 8:2;
  • –XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合;
  • -XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合;
  • -XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合;
  • -XX:+PrintGC:开启打印 gc 信息;
  • -XX:+PrintGCDetails:打印 gc 详细信息。

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

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

相关文章

移动端开发框架mui代码在安卓模拟器上运行2(HbuilderX连接到模拟器)模拟器窗口及多开设置

开发工具 HBuilder X 3.8.12.20230817 注意:开发工具尽量用最新的或较新的。太旧的版本在开发调试过程中可能会出现莫名其妙的问题。 接上篇,移动端开发框架mui代码在安卓模拟器上运行(HbuilderX连接到模拟器),这篇主要…

SkyWalking UI 修改发布Nginx

文章目录 SkyWalking UI修改图标修改路由发布到Nginx添加认证修改路由模式vite.config.ts添加baseNginx配置 SkyWalking UI skywalking-booster-ui下载地址 修改图标 替换 logo.svg 修改路由 router - data - index.ts 发布到Nginx 添加认证 # 安装 yum install -y h…

【STM32】STM32学习笔记-PWM驱动LED呼吸灯 舵机 直流电机(16)

00. 目录 文章目录 00. 目录01. 输出比较相关API1.1 TIM_OC1Init1.2 TIM_OCInitTypeDef结构体1.3 TIM_OCMode1.4 TIM_OutputState1.5 TIM_OutputNState1.6 TIM_OCPolarity1.7 TIM_OCNPolarity1.8 TIM_OCPolarity1.9 TIM_OCNPolarity 02. PWM实现呼吸灯接线图03. PWM实现呼吸灯示…

SetWindowsHookEx: 全局钩子实现键盘记录器

简介 SetWindowsHookEx 钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应…

【后端】Docker学习笔记

文章目录 Docker一、Docker安装(Linux)二、Docker概念三、Docker常用命令四、数据卷五、自定义镜像六、网络七、DockerCompose Docker Docker是一个开源平台,主要基于Go语言构建,它使开发者能够将应用程序及其依赖项打包到一个轻…

idea构建maven项目报错的解决

使用idea创建了一个新的spring项目,maven配置完毕后,报错,引用的依赖不存在。 控制台报错信息如下: 通过查询资料,发现是阿里云的maven仓库中没有这个版本的jar包,导入无法引用到对应的依赖。 解决方法就是…

go的json数据类型处理

json对象转slice package mainimport ("encoding/json""fmt""github.com/gogf/gf/container/garray" )func main() {// JSON 字符串jsonStr : ["apple", "banana", "orange"]//方法一:// 解析 JSON 字…

HTML-基础知识-基本结构,注释,文档说明,字符编码(一)

1.超文本标记语言不分大小写。 2.超文本标签属性名和属性值不区分大小写。 3.超文本标签属性值重复&#xff0c;听取第一个。 4.html结构 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"vi…

单片机的存储、堆栈与程序执行方式

一、单片机存储区域 如图所示位STM32F103ZET6的参数&#xff1a; 单片机的ROM&#xff08;内部FLASH&#xff09;&#xff1a;512KB&#xff0c;用来存放程序代码的空间。 单片机的RAM&#xff1a;64KB&#xff0c;一般都被分配为堆、栈、变量等的空间。 二、堆和栈的概念 …

关于“Python”的核心知识点整理大全53

目录 18.2.7 Django shell 注意 18.3 创建网页&#xff1a;学习笔记主页 18.3.1 映射 URL urls.py urls.py 注意 18.3.2 编写视图 views.py 18.3.3 编写模板 index.html 往期快速传送门&#x1f446;&#xff08;在文章最后&#xff09;&#xff1a; 感谢大家的支…

FPGA - 231227 - 5CSEMA5F31C6 - 电子万年历

TAG - F P G A 、 5 C S E M A 5 F 31 C 6 、电子万年历、 V e r i l o g FPGA、5CSEMA5F31C6、电子万年历、Verilog FPGA、5CSEMA5F31C6、电子万年历、Verilog 顶层模块 module TOP(input CLK,RST,inA,inB,inC,switch_alarm,output led,beep_led,output [41:0] dp );// 按键…

<JavaEE> TCP 的通信机制(一) -- 确认应答 和 超时重传

目录 TCP的通信机制的核心特性 一、确认应答 1&#xff09;什么是确认应答&#xff1f; 2&#xff09;如何“确认”&#xff1f; 3&#xff09;如何“应答”&#xff1f; 二、超时重传 1&#xff09;丢包的概念 2&#xff09;什么是超时重传&#xff1f; 3&#xff09…

【VMware】Windows安装MySQL(5.78版本)及网络配置---图文并茂详细介绍

一 安装MySQL准备工作 ① 连接虚拟机传输MySQL压缩包 先查看虚拟机中的地址 命令&#xff1a; ipconfig 主机连接 在主机连接虚拟机后&#xff0c;将mysql压缩包和Navicat安装包复制到虚拟机下即可 ②解压MySQL压缩包 ③ my文件拷贝mysql安装根目录下 如下图的第一步&…

vue-springboot基于JavaWeb的家装一体化商城平台guptn

针对用户需求开发与设计&#xff0c;该技术尤其在各行业领域发挥了巨大的作用&#xff0c;有效地促进了家装一体化的发展。然而&#xff0c;由于用户量和需求量的增加&#xff0c;信息过载等问题暴露出来&#xff0c;为改善传统线下管理中的不足&#xff0c;本文将提出一套基于…

IntelliJ IDEA常用快捷键

【1】创建内容&#xff08;新建&#xff09;&#xff1a;altinsert 【2】main方法&#xff1a;psvm 【3】输出语句&#xff1a;sout 【4】复制行&#xff1a;ctrld 【5】删除行&#xff1a;ctrly&#xff08;很多编辑器ctrly是前进操作&#xff0c;如果选择 Delete Line&…

Apollo自动驾驶:改变交通运输的游戏规则

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 ChatGPT体验地址 文章目录 前言1. Apollo缓存层2. 本地状态管理库3. 离线同步和冲突解决4. 离线数据同步和离线优先策略结论 &#x1f4f2;&#x1f50c; 构建离线应用&#xff1a;Apollo…

磁盘和文件系统管理

一&#xff1a;磁盘结构&#xff1a; 1.磁盘基础&#xff1a; 扇区固定大小&#xff0c;每个扇区4k。磁盘会进行磨损&#xff0c;损失生命周期。 设备文件&#xff1a; 一切皆文件 设备文件&#xff1a;关联至一个设备驱动程序&#xff0c;进而能够跟与之对应硬件设备进行通…

【2023】通过docker安装hadoop以及常见报错

&#x1f4bb;目录 1、准备2、安装镜像2.1、创建centos-ssh的镜像2.2、创建hadoop的镜像 3、配置ssh网络3.1、搭建同一网段的网络3.2、配置host实现互相之间可以免密登陆3.3、查看是否成功 4、安装配置Hadoop4.1、添加存储文件夹4.2、添加指定配置4.3、同步数据 5、测试启动5.1…

纯CSS的华为充电动画,它来了

&#x1f4e2; 鸿蒙专栏&#xff1a;想学鸿蒙的&#xff0c;冲 &#x1f4e2; C语言专栏&#xff1a;想学C语言的&#xff0c;冲 &#x1f4e2; VUE专栏&#xff1a;想学VUE的&#xff0c;冲这里 &#x1f4e2; Krpano专栏&#xff1a;想学Krpano的&#xff0c;冲 &#x1f514…

Linux文件类型

在 Linux 系统中&#xff1a; b 文件类型&#xff1a;代表块设备文件。块设备文件通常是对应于设备&#xff0c;如硬盘驱动器或其他块设备&#xff0c;使用块级别的 I/O 操作。 c 文件类型&#xff1a;代表字符设备文件。字符设备文件通常是对应于设备&#xff0c;如串口、键盘…